removed errors in previous commit
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.4.1-alpha.1+timestamp.2012.12.24.13.48.18
|
Version 2.4.1-alpha.1+timestamp.2012.12.24.13.54.21
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE REQUEST-----
|
|
||||||
MIICzjCCAbYCAQAwgYgxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczER
|
|
||||||
MA8GA1UEBxMIT2FrIFBhcmsxDzANBgNVBAoTBndlYjJweTEXMBUGA1UEAxMOd3d3
|
|
||||||
LndlYjJweS5jb20xKTAnBgkqhkiG9w0BCQEWGm1hc3NpbW8uZGlwaWVycm9AZ21h
|
|
||||||
aWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6AX4oTjdBThw
|
|
||||||
xdGEDtb+XhvyW58gC9il2z5ewp/AVwYUst1MYPF1jPLv23yn4jkN4c6OExlhgsVi
|
|
||||||
YxsWq8fEg55SEBr3gpH608FOtwicEeIHwufP7OhHiOB1rhUa5B54xIIoh5AMKwIH
|
|
||||||
qvPlLn8Pi8DJGdAoDwUTUsFLWJdt0/XQgjHQOeIrgXRvrGPLWQglQ3/8AqWZ2TLp
|
|
||||||
raBZv9RgXJ8IlArwfEzfdQnfkrmAMOjsBRaf7krQMAF7n+R1SqNWQeFfw//FccC9
|
|
||||||
seHvRkbawjyHL0VezmR/eAUGw8nYZuEjhUEZnrGpD4fRWSxfZuk7nx2EXKh4qOJL
|
|
||||||
kVQHu5/ZOQIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBANjuO4viE6MpTVyMDJNv
|
|
||||||
Cx60q4fq5ej9QU+KDb9A5wTHl6/KRJNd7EPJl07OP1Mm0D2Krp+GfLh7vVLKvxl1
|
|
||||||
G1f4sDkXeAD1OhcqcUEBdS4CzLCYP0RdW9T77lQ5i43C+XBJH3RGzdgofjS41JNY
|
|
||||||
mswCv66mSMb28PoRPYiGLfW/RKO27g+viYrVoJBikntjR86x7hwBUWjpOv+jBk3a
|
|
||||||
jtE39KDj1ID/3eYrkdz3Hz65VvK4rFSY/TwTYzRrTO/4SZjwCZfgcy1BdFRn5aSK
|
|
||||||
pB2fxDLEg/bydBdI78PtxocFBX7qZfm9VWpj8UfN0D+SAFUyesxEuQDPIKO5FHMm
|
|
||||||
Otk=
|
|
||||||
-----END CERTIFICATE REQUEST-----
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpgIBAAKCAQEA6AX4oTjdBThwxdGEDtb+XhvyW58gC9il2z5ewp/AVwYUst1M
|
|
||||||
YPF1jPLv23yn4jkN4c6OExlhgsViYxsWq8fEg55SEBr3gpH608FOtwicEeIHwufP
|
|
||||||
7OhHiOB1rhUa5B54xIIoh5AMKwIHqvPlLn8Pi8DJGdAoDwUTUsFLWJdt0/XQgjHQ
|
|
||||||
OeIrgXRvrGPLWQglQ3/8AqWZ2TLpraBZv9RgXJ8IlArwfEzfdQnfkrmAMOjsBRaf
|
|
||||||
7krQMAF7n+R1SqNWQeFfw//FccC9seHvRkbawjyHL0VezmR/eAUGw8nYZuEjhUEZ
|
|
||||||
nrGpD4fRWSxfZuk7nx2EXKh4qOJLkVQHu5/ZOQIDAQABAoIBAQCAyI+wLPfApgsy
|
|
||||||
QZCjDAI0Ch8Da9dFvAKTJpNCQ5lmtCFZBiwWwu8UROONWCt3DWP/Kb8CKtxM0XJC
|
|
||||||
wA5dWoxg4cd62Pz4pD4suucOAOFfq63TKQfn3yWVe8DV1zEN3Tv7FqOYWwPl+0J2
|
|
||||||
SNm0bSIb1+3HPhp9+7s1+8PucF6tfnyRMtZAXN0MURsMLHhxepi1hd1nxEhFt2gg
|
|
||||||
F57CQVTMFnGZd9swSgJhFbMbQeBjBd/KSE8Jf+Gr3jMbpyQoqAsJrmikmz1ONvYA
|
|
||||||
+FlIDxNFJZWXYTXld3amXXjPyDgc4VbmrtTTYHpZHjwecEf/Sj1J7MAGCXJoAwuF
|
|
||||||
7LeByp1hAoGBAPoLl1VFyC0p3Iu2wViW1CxT2inb5eH7IuosPxG41vFKG/wom+Ww
|
|
||||||
bT8BUwGwGXJv/PIMbAKbJ8z7SZtSkY4I+hL51r+rplwwnxW7AfuRB2wK3KEoBtUN
|
|
||||||
EdmNlVW2DNIIJitv2Cszx7z1myRhaOj9xNz6cI5FhkGAMmE+rr8Q1e6LAoGBAO2M
|
|
||||||
gjfu1/iI7QWXG9tS3/TE3n7JVXpt222iJh4Df6oYAa93snU0OAAV3DiURpDmbi43
|
|
||||||
qpryiDgaM5ONCmOgYs3wM7Vpc5PdKtwZdIOcMP78Vk7hwaAsFn1k+WjIXlPcRWLi
|
|
||||||
3iAAzjz+juXa6BGxBcQf2PmPuEEOwBrnVaLfIjPLAoGBAI6Boqs3zSFoVUjPTJxX
|
|
||||||
we7Nj24B5J+JiNmbhApupRn5mb95yXf7uBeLgqpYmfgtuSSeTcSidumNYeMDCO/B
|
|
||||||
T/0WpPyyMGskTtaMsVGV03wRKLM0Y8hy3XR3C+BAlEfz2wUwhiwBI9oexF/UoH0B
|
|
||||||
fHxQw2tiVmToUk438lH0n2iHAoGBAN5iIPIN9j+kqAgIu7pqbmDuAME+6HfR6o9L
|
|
||||||
MlX8voJVMRa8fuO8PATQcjbBkQJLxrAbyup9zMqAtPIYIra7ymOy0CWwD9RIQ7yD
|
|
||||||
VBF1omTDhGUacbLqMy+23MqccboeRxLZAkuBlZGCWfKTKZiOWbCOhAi15C97iJpn
|
|
||||||
IUN1ksZbAoGBANY7zwfUFPeKoChU92Jsub0daLGFBX8IRkRmDGPUvSHtMG2LRUdX
|
|
||||||
s12Y2wCVX9nDwVHvVo1E+Xnc1UeXJZI6r9P0GnJqhTf/4Z9XULCb4E/nJdrd1zcq
|
|
||||||
VYnb6p0ECh1N6syJ+YeBLG6aWKU0sLfri8LNxTFRza2lVP6aRLt+iE6M
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
Vendored
BIN
Binary file not shown.
@@ -1,640 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
docstring
|
|
||||||
"""
|
|
||||||
|
|
||||||
__author__ = "Gu Yingbo (tensiongyb@gmail.com)"
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import base64
|
|
||||||
import asyncore
|
|
||||||
import asynchat
|
|
||||||
import rfc822
|
|
||||||
import socket
|
|
||||||
import thread
|
|
||||||
import signal
|
|
||||||
import collections
|
|
||||||
from traceback import format_exc
|
|
||||||
from urllib import unquote, splitquery
|
|
||||||
from urlparse import urlparse
|
|
||||||
try:
|
|
||||||
import cStringIO as StringIO
|
|
||||||
except ImportError:
|
|
||||||
import StringIO
|
|
||||||
|
|
||||||
RN = '\r\n'
|
|
||||||
RNRN = '\r\n\r\n'
|
|
||||||
QUOTED_SLASH = re.compile("(?i)%2F")
|
|
||||||
|
|
||||||
COMMA_SEPARATED_HEADERS = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
|
|
||||||
'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
|
|
||||||
'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
|
|
||||||
'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
|
|
||||||
'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
|
|
||||||
'WWW-AUTHENTICATE']
|
|
||||||
|
|
||||||
class FIFO(list):
|
|
||||||
def is_empty(self):
|
|
||||||
return len(self)==0
|
|
||||||
def push(self,data):
|
|
||||||
self.append(data)
|
|
||||||
def first(self):
|
|
||||||
return self[0] if len(self) else None
|
|
||||||
|
|
||||||
class RequestHandler(asynchat.async_chat):
|
|
||||||
|
|
||||||
def __init__(self, sock, server):
|
|
||||||
asynchat.async_chat.__init__(self, sock)
|
|
||||||
self.server = server
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.ac_in_buffer = ''
|
|
||||||
self.ac_out_buffer = ''
|
|
||||||
self.producer_fifo.clear() # = collections.deque()
|
|
||||||
self.set_terminator(RNRN)
|
|
||||||
self.process = "reading headers"
|
|
||||||
self.started_response = False
|
|
||||||
self.status = ""
|
|
||||||
self.outheaders = []
|
|
||||||
self.sent_headers = False
|
|
||||||
self.close_connection = False
|
|
||||||
self.chunked_write = False
|
|
||||||
|
|
||||||
self.rfile = StringIO.StringIO()
|
|
||||||
|
|
||||||
self.environ = {
|
|
||||||
"wsgi.version": (1, 0),
|
|
||||||
"wsgi.url_scheme": "http",
|
|
||||||
"wsgi.multithread": False,
|
|
||||||
"wsgi.multiprocess": False,
|
|
||||||
"wsgi.run_once": False,
|
|
||||||
"wsgi.errors": sys.stderr,
|
|
||||||
}
|
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
|
||||||
"""Buffer the data"""
|
|
||||||
if self.process == "reading chunked":
|
|
||||||
self.line_buffer += data
|
|
||||||
else:
|
|
||||||
self.rfile.write(data)
|
|
||||||
|
|
||||||
def found_terminator(self):
|
|
||||||
if self.process == "reading headers":
|
|
||||||
self.rfile.write(RNRN)
|
|
||||||
self.rfile.seek(0)
|
|
||||||
try:
|
|
||||||
self.parse_request()
|
|
||||||
except:
|
|
||||||
self.simple_response("500 Internal Server Error", format_exc())
|
|
||||||
return
|
|
||||||
|
|
||||||
if not self.read_chunked:
|
|
||||||
if self.environ["REQUEST_METHOD"].upper() == "POST":
|
|
||||||
cl = int(self.environ["CONTENT_LENGTH"])
|
|
||||||
self.rfile = StringIO.StringIO()
|
|
||||||
self.environ["wsgi.input"] = self.rfile
|
|
||||||
self.process = "dealing post"
|
|
||||||
self.set_terminator(cl)
|
|
||||||
else:
|
|
||||||
return self.wsgi_response()
|
|
||||||
else:
|
|
||||||
self.rfile = StringIO.StringIO()
|
|
||||||
self.environ["wsgi.input"] = self.rfile
|
|
||||||
self.process = "reading chunked"
|
|
||||||
self.set_terminator(RN)
|
|
||||||
self.line_buffer = ""
|
|
||||||
self.cl = 0
|
|
||||||
elif self.process == "dealing post":
|
|
||||||
self.rfile.seek(0)
|
|
||||||
return self.wsgi_response()
|
|
||||||
elif self.process == "reading chunked":
|
|
||||||
line = self.line_buffer.split(";", 1)
|
|
||||||
chunk_size = int(line.pop(0), 16)
|
|
||||||
if chunk_size <= 0:
|
|
||||||
self.process = "reading tail headers"
|
|
||||||
self.set_terminator(RNRN)
|
|
||||||
else:
|
|
||||||
self.cl += chunk_size
|
|
||||||
self.process = "get chunked"
|
|
||||||
self.set_terminator(self.cl+2) # browsers sometimes over-send
|
|
||||||
elif self.process == "get chunked":
|
|
||||||
crlf = self.rfile.getvalue()[-2:]
|
|
||||||
if not crlf != RN:
|
|
||||||
self.simple_response("400 Bad Request",
|
|
||||||
"Bad chunked transfer coding "
|
|
||||||
"(expected '\\r\\n', got %r)" % crlf)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.process = "reading chunked"
|
|
||||||
self.set_terminator(RN)
|
|
||||||
self.rfile.seek(-2, 2)
|
|
||||||
self.rfile.truncate()
|
|
||||||
elif self.process == "reading tail headers":
|
|
||||||
self.read_headers()
|
|
||||||
self.rfile.seek(0)
|
|
||||||
self.environ["CONTENT_LENGTH"] = str(self.cl) or ""
|
|
||||||
return self.wsgi_response()
|
|
||||||
|
|
||||||
def reset_when_done(self):
|
|
||||||
self.producer_fifo.append('\0')
|
|
||||||
|
|
||||||
def refill_buffer (self):
|
|
||||||
while 1:
|
|
||||||
if len(self.producer_fifo):
|
|
||||||
p = self.producer_fifo.first()
|
|
||||||
# a 'None' in the producer fifo is a sentinel,
|
|
||||||
# telling us to close the channel.
|
|
||||||
if p == 0:
|
|
||||||
if not self.ac_out_buffer:
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
self.reset()
|
|
||||||
return
|
|
||||||
elif p is None:
|
|
||||||
if not self.ac_out_buffer:
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
self.close()
|
|
||||||
return
|
|
||||||
elif isinstance(p, str):
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
self.ac_out_buffer = self.ac_out_buffer + p
|
|
||||||
return
|
|
||||||
data = p.more()
|
|
||||||
if data:
|
|
||||||
self.ac_out_buffer = self.ac_out_buffer + data
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
def wsgi_response(self):
|
|
||||||
try:
|
|
||||||
self.respond()
|
|
||||||
except:
|
|
||||||
self.simple_response("500 Internal Server Error", format_exc())
|
|
||||||
else:
|
|
||||||
if self.close_connection or ( not self.server.keep_going ):
|
|
||||||
self.close_when_done()
|
|
||||||
else:
|
|
||||||
self.reset_when_done()
|
|
||||||
|
|
||||||
def readable(self):
|
|
||||||
return self.server.keep_going and not self.writable() and \
|
|
||||||
asynchat.async_chat.readable(self)
|
|
||||||
|
|
||||||
def handle_expt(self):
|
|
||||||
asynchat.async_chat.handle_expt(self)
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def handle_error(self):
|
|
||||||
asynchat.async_chat.handle_error(self)
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def parse_request(self):
|
|
||||||
"""
|
|
||||||
Parse the next HTTP request start-line and message-headers.
|
|
||||||
HTTP/1.1 connections are persistent by default. If a client
|
|
||||||
requests a page, then idles (leaves the connection open),
|
|
||||||
then rfile.readline() will raise socket.error("timed out").
|
|
||||||
Note that it does this based on the value given to settimeout(),
|
|
||||||
and doesn't need the client to request or acknowledge the close
|
|
||||||
(although your TCP stack might suffer for it: cf Apache's history
|
|
||||||
with FIN_WAIT_2).
|
|
||||||
"""
|
|
||||||
request_line = self.rfile.readline()
|
|
||||||
if not request_line:
|
|
||||||
# Force self.ready = False so the connection will close.
|
|
||||||
self.ready = False
|
|
||||||
return
|
|
||||||
|
|
||||||
if request_line == RN:
|
|
||||||
# RFC 2616 sec 4.1: "...if the server is reading the protocol
|
|
||||||
# stream at the beginning of a message and receives a CRLF
|
|
||||||
# first, it should ignore the CRLF."
|
|
||||||
# But only ignore one leading line! else we enable a DoS.
|
|
||||||
request_line = self.rfile.readline()
|
|
||||||
if not request_line:
|
|
||||||
self.ready = False
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self.server
|
|
||||||
environ = self.environ
|
|
||||||
environ["SERVER_SOFTWARE"] = "%s WSGI Server" % server.version
|
|
||||||
|
|
||||||
method, path, req_protocol = request_line.strip().split(" ", 2)
|
|
||||||
environ["REQUEST_METHOD"] = method
|
|
||||||
|
|
||||||
# path may be an abs_path (including "http://host.domain.tld");
|
|
||||||
scheme, location, path, params, qs, frag = urlparse(path)
|
|
||||||
|
|
||||||
if frag:
|
|
||||||
self.simple_response("400 Bad Request",
|
|
||||||
"Illegal #fragment in Request-URI.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if scheme:
|
|
||||||
environ["wsgi.url_scheme"] = scheme
|
|
||||||
if params:
|
|
||||||
path = path + ";" + params
|
|
||||||
|
|
||||||
# Unquote the path+params (e.g. "/this%20path" -> "this path").
|
|
||||||
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
|
||||||
#
|
|
||||||
# But note that "...a URI must be separated into its components
|
|
||||||
# before the escaped characters within those components can be
|
|
||||||
# safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
|
|
||||||
atoms = [unquote(x) for x in QUOTED_SLASH.split(path)]
|
|
||||||
path = "%2F".join(atoms)
|
|
||||||
|
|
||||||
environ["SCRIPT_NAME"] = ""
|
|
||||||
environ["PATH_INFO"] = path
|
|
||||||
##if path == "*":
|
|
||||||
## # This means, of course, that the last wsgi_app (shortest path)
|
|
||||||
## # will always handle a URI of "*".
|
|
||||||
## environ["SCRIPT_NAME"] = ""
|
|
||||||
## environ["PATH_INFO"] = "*"
|
|
||||||
## self.wsgi_app = server.mount_points[-1][1]
|
|
||||||
##else:
|
|
||||||
## for mount_point, wsgi_app in server.mount_points:
|
|
||||||
## # The mount_points list should be sorted by length, descending.
|
|
||||||
## if path.startswith(mount_point + "/") or path == mount_point:
|
|
||||||
## environ["SCRIPT_NAME"] = mount_point
|
|
||||||
## environ["PATH_INFO"] = path[len(mount_point):]
|
|
||||||
## self.wsgi_app = wsgi_app
|
|
||||||
## break
|
|
||||||
## else:
|
|
||||||
## self.simple_response("404 Not Found")
|
|
||||||
## return
|
|
||||||
|
|
||||||
# Note that, like wsgiref and most other WSGI servers,
|
|
||||||
# we unquote the path but not the query string.
|
|
||||||
environ["QUERY_STRING"] = qs
|
|
||||||
|
|
||||||
# Compare request and server HTTP protocol versions, in case our
|
|
||||||
# server does not support the requested protocol. Limit our output
|
|
||||||
# to min(req, server). We want the following output:
|
|
||||||
# request server actual written supported response
|
|
||||||
# protocol protocol response protocol feature set
|
|
||||||
# a 1.0 1.0 1.0 1.0
|
|
||||||
# b 1.0 1.1 1.1 1.0
|
|
||||||
# c 1.1 1.0 1.0 1.0
|
|
||||||
# d 1.1 1.1 1.1 1.1
|
|
||||||
# Notice that, in (b), the response will be "HTTP/1.1" even though
|
|
||||||
# the client only understands 1.0. RFC 2616 10.5.6 says we should
|
|
||||||
# only return 505 if the _major_ version is different.
|
|
||||||
rp = int(req_protocol[5]), int(req_protocol[7])
|
|
||||||
sp = int(server.protocol[5]), int(server.protocol[7])
|
|
||||||
if sp[0] != rp[0]:
|
|
||||||
self.simple_response("505 HTTP Version Not Supported")
|
|
||||||
return
|
|
||||||
# Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
|
|
||||||
environ["SERVER_PROTOCOL"] = req_protocol
|
|
||||||
# set a non-standard environ entry so the WSGI app can know what
|
|
||||||
# the *real* server protocol is (and what features to support).
|
|
||||||
# See http://www.faqs.org/rfcs/rfc2145.html.
|
|
||||||
environ["ACTUAL_SERVER_PROTOCOL"] = server.protocol
|
|
||||||
self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
|
|
||||||
|
|
||||||
# If the Request-URI was an absoluteURI, use its location atom.
|
|
||||||
if location:
|
|
||||||
environ["SERVER_NAME"] = location
|
|
||||||
|
|
||||||
# then all the http headers
|
|
||||||
try:
|
|
||||||
self.read_headers()
|
|
||||||
except ValueError, ex:
|
|
||||||
self.simple_response("400 Bad Request", repr(ex.args))
|
|
||||||
return
|
|
||||||
|
|
||||||
creds = environ.get("HTTP_AUTHORIZATION", "").split(" ", 1)
|
|
||||||
environ["AUTH_TYPE"] = creds[0]
|
|
||||||
if creds[0].lower() == 'basic':
|
|
||||||
user, pw = base64.decodestring(creds[1]).split(":", 1)
|
|
||||||
environ["REMOTE_USER"] = user
|
|
||||||
|
|
||||||
# Persistent connection support
|
|
||||||
if self.response_protocol == "HTTP/1.1":
|
|
||||||
if environ.get("HTTP_CONNECTION", "") == "close":
|
|
||||||
self.close_connection = True
|
|
||||||
else:
|
|
||||||
# HTTP/1.0
|
|
||||||
if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
|
|
||||||
self.close_connection = True
|
|
||||||
|
|
||||||
# Transfer-Encoding support
|
|
||||||
te = None
|
|
||||||
if self.response_protocol == "HTTP/1.1":
|
|
||||||
te = environ.get("HTTP_TRANSFER_ENCODING")
|
|
||||||
if te:
|
|
||||||
te = [x.strip().lower() for x in te.split(",") if x.strip()]
|
|
||||||
|
|
||||||
read_chunked = False
|
|
||||||
|
|
||||||
if te:
|
|
||||||
for enc in te:
|
|
||||||
if enc == "chunked":
|
|
||||||
read_chunked = True
|
|
||||||
else:
|
|
||||||
# Note that, even if we see "chunked", we must reject
|
|
||||||
# if there is an extension we don't recognize.
|
|
||||||
self.simple_response("501 Unimplemented")
|
|
||||||
self.close_connection = True
|
|
||||||
return
|
|
||||||
|
|
||||||
self.read_chunked = read_chunked
|
|
||||||
return
|
|
||||||
|
|
||||||
if read_chunked:
|
|
||||||
if not self.decode_chunked():
|
|
||||||
return
|
|
||||||
|
|
||||||
# From PEP 333:
|
|
||||||
# "Servers and gateways that implement HTTP 1.1 must provide
|
|
||||||
# transparent support for HTTP 1.1's "expect/continue" mechanism.
|
|
||||||
# This may be done in any of several ways:
|
|
||||||
# 1. Respond to requests containing an Expect: 100-continue request
|
|
||||||
# with an immediate "100 Continue" response, and proceed normally.
|
|
||||||
# 2. Proceed with the request normally, but provide the application
|
|
||||||
# with a wsgi.input stream that will send the "100 Continue"
|
|
||||||
# response if/when the application first attempts to read from
|
|
||||||
# the input stream. The read request must then remain blocked
|
|
||||||
# until the client responds.
|
|
||||||
# 3. Wait until the client decides that the server does not support
|
|
||||||
# expect/continue, and sends the request body on its own.
|
|
||||||
# (This is suboptimal, and is not recommended.)
|
|
||||||
#
|
|
||||||
# We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
|
|
||||||
# but it seems like it would be a big slowdown for such a rare case.
|
|
||||||
if environ.get("HTTP_EXPECT", "") == "100-continue":
|
|
||||||
self.simple_response(100)
|
|
||||||
|
|
||||||
self.ready = True
|
|
||||||
|
|
||||||
def new_header(self,k,v):
|
|
||||||
if k:
|
|
||||||
environ = self.environ
|
|
||||||
envname = 'HTTP_'+k
|
|
||||||
if k in COMMA_SEPARATED_HEADERS:
|
|
||||||
existing = environ.get(envname)
|
|
||||||
if existing:
|
|
||||||
v = ", ".join((existing, v))
|
|
||||||
environ[envname] = v
|
|
||||||
|
|
||||||
def read_headers(self):
|
|
||||||
"""Read header lines from the incoming stream."""
|
|
||||||
k = v = None
|
|
||||||
while True:
|
|
||||||
line = self.rfile.readline()
|
|
||||||
if not line or '\0' in line:
|
|
||||||
# No more data--illegal end of headers
|
|
||||||
raise ValueError("Illegal headers")
|
|
||||||
elif line == RN:
|
|
||||||
# Normal end of headers
|
|
||||||
self.new_header(k,v)
|
|
||||||
break
|
|
||||||
elif line[0] in ' \t':
|
|
||||||
v += line.strip()
|
|
||||||
else:
|
|
||||||
self.new_header(k,v)
|
|
||||||
k, v = line.split(":", 1)
|
|
||||||
k, v = k.strip().upper(), v.strip()
|
|
||||||
|
|
||||||
environ = self.environ
|
|
||||||
ct = environ.pop("HTTP_CONTENT_TYPE", None)
|
|
||||||
if ct:
|
|
||||||
environ["CONTENT_TYPE"] = ct
|
|
||||||
cl = environ.pop("HTTP_CONTENT_LENGTH", None)
|
|
||||||
if cl:
|
|
||||||
environ["CONTENT_LENGTH"] = cl
|
|
||||||
|
|
||||||
def decode_chunked(self):
|
|
||||||
"""Decode the 'chunked' transfer coding."""
|
|
||||||
cl = 0
|
|
||||||
data = StringIO.StringIO()
|
|
||||||
while True:
|
|
||||||
line = self.rfile.readline().strip().split(";", 1)
|
|
||||||
chunk_size = int(line.pop(0), 16)
|
|
||||||
if chunk_size <= 0:
|
|
||||||
break
|
|
||||||
## if line: chunk_extension = line[0]
|
|
||||||
cl += chunk_size
|
|
||||||
data.write(self.rfile.read(chunk_size))
|
|
||||||
crlf = self.rfile.read(2)
|
|
||||||
if crlf != RN:
|
|
||||||
self.simple_response("400 Bad Request",
|
|
||||||
"Bad chunked transfer coding "
|
|
||||||
"(expected '\\r\\n', got %r)" % crlf)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Grab any trailer headers
|
|
||||||
self.read_headers()
|
|
||||||
|
|
||||||
data.seek(0)
|
|
||||||
self.environ["wsgi.input"] = data
|
|
||||||
self.environ["CONTENT_LENGTH"] = str(cl) or ""
|
|
||||||
return True
|
|
||||||
|
|
||||||
def respond(self):
|
|
||||||
"""
|
|
||||||
Call the appropriate WSGI app and write its iterable output.
|
|
||||||
"""
|
|
||||||
response = self.server.wsgi_app(self.environ, self.start_response)
|
|
||||||
try:
|
|
||||||
for chunk in response:
|
|
||||||
# "The start_response callable must not actually transmit
|
|
||||||
# the response headers. Instead, it must store them for the
|
|
||||||
# server or gateway to transmit only after the first
|
|
||||||
# iteration of the application return value that yields
|
|
||||||
# a NON-EMPTY string, or upon the application's first
|
|
||||||
# invocation of the write() callable." (PEP 333)
|
|
||||||
if chunk:
|
|
||||||
print 'sending',chunk
|
|
||||||
self.write(chunk)
|
|
||||||
print 'sent!'
|
|
||||||
finally:
|
|
||||||
if hasattr(response, "close"):
|
|
||||||
response.close()
|
|
||||||
|
|
||||||
if not self.sent_headers:
|
|
||||||
self.send_headers()
|
|
||||||
if self.chunked_write:
|
|
||||||
self.push("0\r\n")
|
|
||||||
|
|
||||||
def simple_response(self, status, msg=""):
|
|
||||||
"""Write a simple response back to the client."""
|
|
||||||
status = str(status)
|
|
||||||
buf = ["%s %s\r\n" % (self.server.protocol, status),
|
|
||||||
"Content-Length: %s\r\n" % len(msg)]
|
|
||||||
|
|
||||||
if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
|
|
||||||
# Request Entity Too Large
|
|
||||||
self.close_connection = True
|
|
||||||
buf.append("Connection: close\r\n")
|
|
||||||
|
|
||||||
buf.append(RN)
|
|
||||||
if msg:
|
|
||||||
buf.append(msg)
|
|
||||||
self.push(''.join(buf))
|
|
||||||
|
|
||||||
if self.close_connection or ( not self.server.keep_going ):
|
|
||||||
self.close_when_done()
|
|
||||||
else:
|
|
||||||
self.reset_when_done()
|
|
||||||
|
|
||||||
def start_response(self, status, headers, exc_info = None):
|
|
||||||
"""WSGI callable to begin the HTTP response."""
|
|
||||||
if self.started_response:
|
|
||||||
if not exc_info:
|
|
||||||
raise AssertionError("WSGI start_response called a second "
|
|
||||||
"time with no exc_info.")
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
raise exc_info[0], exc_info[1], exc_info[2]
|
|
||||||
finally:
|
|
||||||
exc_info = None
|
|
||||||
self.started_response = True
|
|
||||||
self.status = status
|
|
||||||
self.outheaders.extend(headers)
|
|
||||||
return self.write
|
|
||||||
|
|
||||||
def write(self, chunk):
|
|
||||||
"""
|
|
||||||
WSGI callable to write unbuffered data to the client.
|
|
||||||
|
|
||||||
This method is also used internally by start_response (to write
|
|
||||||
data from the iterable returned by the WSGI application).
|
|
||||||
"""
|
|
||||||
if not self.started_response:
|
|
||||||
raise AssertionError("WSGI write called before start_response.")
|
|
||||||
|
|
||||||
if not self.sent_headers:
|
|
||||||
self.send_headers()
|
|
||||||
|
|
||||||
if self.chunked_write and chunk:
|
|
||||||
buf = [hex(len(chunk))[2:], RN, chunk, RN]
|
|
||||||
self.push(''.join(buf))
|
|
||||||
else:
|
|
||||||
self.push(chunk)
|
|
||||||
|
|
||||||
def send_headers(self):
|
|
||||||
"""
|
|
||||||
Assert, process, and send the HTTP response message-headers.
|
|
||||||
"""
|
|
||||||
self.sent_headers = True
|
|
||||||
hkeys = [key.lower() for key, value in self.outheaders]
|
|
||||||
status = int(self.status[:3])
|
|
||||||
|
|
||||||
if status == 413:
|
|
||||||
# Request Entity Too Large. Close conn to avoid garbage.
|
|
||||||
self.close_connection = True
|
|
||||||
elif "content-length" not in hkeys:
|
|
||||||
# "All 1xx (informational), 204 (no content),
|
|
||||||
# and 304 (not modified) responses MUST NOT
|
|
||||||
# include a message-body." So no point chunking.
|
|
||||||
if status < 200 or status in (204, 205, 304):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if self.response_protocol == 'HTTP/1.1':
|
|
||||||
# Use the chunked transfer-coding
|
|
||||||
self.chunked_write = True
|
|
||||||
self.outheaders.append(("Transfer-Encoding", "chunked"))
|
|
||||||
else:
|
|
||||||
# Closing the conn is the only way to determine len.
|
|
||||||
self.close_connection = True
|
|
||||||
|
|
||||||
if "connection" not in hkeys:
|
|
||||||
if self.response_protocol == 'HTTP/1.1':
|
|
||||||
if self.close_connection:
|
|
||||||
self.outheaders.append(("Connection", "close"))
|
|
||||||
else:
|
|
||||||
if not self.close_connection:
|
|
||||||
self.outheaders.append(("Connection", "Keep-Alive"))
|
|
||||||
|
|
||||||
if "date" not in hkeys:
|
|
||||||
self.outheaders.append(("Date", rfc822.formatdate()))
|
|
||||||
|
|
||||||
server = self.server
|
|
||||||
|
|
||||||
if "server" not in hkeys:
|
|
||||||
self.outheaders.append(("Server", server.version))
|
|
||||||
|
|
||||||
buf = [server.protocol, " ", self.status, RN]
|
|
||||||
try:
|
|
||||||
buf += [k + ": " + v + RN for k, v in self.outheaders]
|
|
||||||
except TypeError:
|
|
||||||
if not isinstance(k, str):
|
|
||||||
raise TypeError("WSGI response header key %r is not a string.")
|
|
||||||
if not isinstance(v, str):
|
|
||||||
raise TypeError("WSGI response header value %r is not a string.")
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
buf.append(RN)
|
|
||||||
self.push(''.join(buf))
|
|
||||||
|
|
||||||
class WSGIServer(asyncore.dispatcher):
|
|
||||||
version = "Asynwsgi Server/1.0 alpha"
|
|
||||||
protocol = "HTTP/1.1"
|
|
||||||
def __init__(self, bind_addr, wsgi_app, server_name=None):
|
|
||||||
asyncore.dispatcher.__init__ (self)
|
|
||||||
self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.set_reuse_addr()
|
|
||||||
self.bind(bind_addr)
|
|
||||||
self.listen(1024)
|
|
||||||
self.keep_going = True
|
|
||||||
self.wsgi_app = wsgi_app
|
|
||||||
|
|
||||||
if not server_name:
|
|
||||||
server_name = socket.gethostname()
|
|
||||||
self.server_name = server_name
|
|
||||||
|
|
||||||
def writable(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def readable(self):
|
|
||||||
return self.accepting
|
|
||||||
|
|
||||||
def handle_accept(self):
|
|
||||||
try:
|
|
||||||
conn, addr = self.accept()
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
RequestHandler(conn, self)
|
|
||||||
|
|
||||||
def reload(self, signum, frame):
|
|
||||||
print 'reloading...'
|
|
||||||
self.keep_going = False
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def stop(self, signum, frame):
|
|
||||||
asyncore.close_all()
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
signal.signal(signal.SIGTERM, self.stop)
|
|
||||||
signal.signal(signal.SIGINT, self.stop)
|
|
||||||
asyncore.loop(timeout=0.1, use_poll=False)
|
|
||||||
|
|
||||||
def demo_app(environ, start_response):
|
|
||||||
write = start_response('200 OK', [('content-type', 'text/html')])
|
|
||||||
return ["<html><body><h1>Hello World!</h1><br />%s</body></html>"%time.ctime()]
|
|
||||||
|
|
||||||
def test_client(address='127.0.0.1:8000'):
|
|
||||||
time.sleep(3)
|
|
||||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
ip,port = address.split(':',1)
|
|
||||||
server.connect((ip,int(port)))
|
|
||||||
server.send('GET /\r\n\r\n')
|
|
||||||
while True:
|
|
||||||
sys.stdout.write(server.recv(1))
|
|
||||||
sys.stdout.write('CLOSE\n')
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
#thread.start_new_thread(test_client,())
|
|
||||||
#thread.start_new_thread(test_client,())
|
|
||||||
#thread.start_new_thread(test_client,())
|
|
||||||
WSGIServer(('127.0.0.1', 8000), demo_app).start()
|
|
||||||
@@ -1,630 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
docstring
|
|
||||||
"""
|
|
||||||
|
|
||||||
__author__ = "Gu Yingbo (tensiongyb@gmail.com)"
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import base64
|
|
||||||
import asyncore
|
|
||||||
import asynchat
|
|
||||||
import rfc822
|
|
||||||
import socket
|
|
||||||
import thread
|
|
||||||
import signal
|
|
||||||
from traceback import format_exc
|
|
||||||
from urllib import unquote, splitquery
|
|
||||||
from urlparse import urlparse
|
|
||||||
try:
|
|
||||||
import cStringIO as StringIO
|
|
||||||
except ImportError:
|
|
||||||
import StringIO
|
|
||||||
|
|
||||||
RN = '\r\n'
|
|
||||||
RNRN = '\r\n\r\n'
|
|
||||||
QUOTED_SLASH = re.compile("(?i)%2F")
|
|
||||||
|
|
||||||
COMMA_SEPARATED_HEADERS = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
|
|
||||||
'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
|
|
||||||
'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
|
|
||||||
'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
|
|
||||||
'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
|
|
||||||
'WWW-AUTHENTICATE']
|
|
||||||
|
|
||||||
class RequestHandler(asynchat.async_chat):
|
|
||||||
|
|
||||||
def __init__(self, sock, server):
|
|
||||||
asynchat.async_chat.__init__(self, sock)
|
|
||||||
self.server = server
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.ac_in_buffer = ''
|
|
||||||
self.ac_out_buffer = ''
|
|
||||||
self.producer_fifo = asynchat.fifo()
|
|
||||||
self.set_terminator(RNRN)
|
|
||||||
self.process = "reading headers"
|
|
||||||
self.started_response = False
|
|
||||||
self.status = ""
|
|
||||||
self.outheaders = []
|
|
||||||
self.sent_headers = False
|
|
||||||
self.close_connection = False
|
|
||||||
self.chunked_write = False
|
|
||||||
|
|
||||||
self.rfile = StringIO.StringIO()
|
|
||||||
|
|
||||||
self.environ = {
|
|
||||||
"wsgi.version": (1, 0),
|
|
||||||
"wsgi.url_scheme": "http",
|
|
||||||
"wsgi.multithread": False,
|
|
||||||
"wsgi.multiprocess": False,
|
|
||||||
"wsgi.run_once": False,
|
|
||||||
"wsgi.errors": sys.stderr,
|
|
||||||
}
|
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
|
||||||
"""Buffer the data"""
|
|
||||||
if self.process == "reading chunked":
|
|
||||||
self.line_buffer += data
|
|
||||||
else:
|
|
||||||
self.rfile.write(data)
|
|
||||||
|
|
||||||
def found_terminator(self):
|
|
||||||
if self.process == "reading headers":
|
|
||||||
self.rfile.write(RNRN)
|
|
||||||
self.rfile.seek(0)
|
|
||||||
try:
|
|
||||||
self.parse_request()
|
|
||||||
except:
|
|
||||||
self.simple_response("500 Internal Server Error", format_exc())
|
|
||||||
return
|
|
||||||
|
|
||||||
if not self.read_chunked:
|
|
||||||
if self.environ["REQUEST_METHOD"].upper() == "POST":
|
|
||||||
cl = int(self.environ["CONTENT_LENGTH"])
|
|
||||||
self.rfile = StringIO.StringIO()
|
|
||||||
self.environ["wsgi.input"] = self.rfile
|
|
||||||
self.process = "dealing post"
|
|
||||||
self.set_terminator(cl)
|
|
||||||
else:
|
|
||||||
return self.wsgi_response()
|
|
||||||
else:
|
|
||||||
self.rfile = StringIO.StringIO()
|
|
||||||
self.environ["wsgi.input"] = self.rfile
|
|
||||||
self.process = "reading chunked"
|
|
||||||
self.set_terminator(RN)
|
|
||||||
self.line_buffer = ""
|
|
||||||
self.cl = 0
|
|
||||||
elif self.process == "dealing post":
|
|
||||||
self.rfile.seek(0)
|
|
||||||
return self.wsgi_response()
|
|
||||||
elif self.process == "reading chunked":
|
|
||||||
line = self.line_buffer.split(";", 1)
|
|
||||||
chunk_size = int(line.pop(0), 16)
|
|
||||||
if chunk_size <= 0:
|
|
||||||
self.process = "reading tail headers"
|
|
||||||
self.set_terminator(RNRN)
|
|
||||||
else:
|
|
||||||
self.cl += chunk_size
|
|
||||||
self.process = "get chunked"
|
|
||||||
self.set_terminator(self.cl+2) # browsers sometimes over-send
|
|
||||||
elif self.process == "get chunked":
|
|
||||||
crlf = self.rfile.getvalue()[-2:]
|
|
||||||
if not crlf != RN:
|
|
||||||
self.simple_response("400 Bad Request",
|
|
||||||
"Bad chunked transfer coding "
|
|
||||||
"(expected '\\r\\n', got %r)" % crlf)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.process = "reading chunked"
|
|
||||||
self.set_terminator(RN)
|
|
||||||
self.rfile.seek(-2, 2)
|
|
||||||
self.rfile.truncate()
|
|
||||||
elif self.process == "reading tail headers":
|
|
||||||
self.read_headers()
|
|
||||||
self.rfile.seek(0)
|
|
||||||
self.environ["CONTENT_LENGTH"] = str(self.cl) or ""
|
|
||||||
return self.wsgi_response()
|
|
||||||
|
|
||||||
def reset_when_done(self):
|
|
||||||
self.producer_fifo.push(0)
|
|
||||||
|
|
||||||
def refill_buffer (self):
|
|
||||||
while 1:
|
|
||||||
if len(self.producer_fifo):
|
|
||||||
p = self.producer_fifo.first()
|
|
||||||
# a 'None' in the producer fifo is a sentinel,
|
|
||||||
# telling us to close the channel.
|
|
||||||
if p == 0:
|
|
||||||
if not self.ac_out_buffer:
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
self.reset()
|
|
||||||
return
|
|
||||||
elif p is None:
|
|
||||||
if not self.ac_out_buffer:
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
self.close()
|
|
||||||
return
|
|
||||||
elif isinstance(p, str):
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
self.ac_out_buffer = self.ac_out_buffer + p
|
|
||||||
return
|
|
||||||
data = p.more()
|
|
||||||
if data:
|
|
||||||
self.ac_out_buffer = self.ac_out_buffer + data
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.producer_fifo.pop()
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
def wsgi_response(self):
|
|
||||||
try:
|
|
||||||
self.respond()
|
|
||||||
except:
|
|
||||||
self.simple_response("500 Internal Server Error", format_exc())
|
|
||||||
else:
|
|
||||||
if self.close_connection or ( not self.server.keep_going ):
|
|
||||||
self.close_when_done()
|
|
||||||
else:
|
|
||||||
self.reset_when_done()
|
|
||||||
|
|
||||||
def readable(self):
|
|
||||||
return self.server.keep_going and not self.writable() and \
|
|
||||||
asynchat.async_chat.readable(self)
|
|
||||||
|
|
||||||
def handle_expt(self):
|
|
||||||
asynchat.async_chat.handle_expt(self)
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def handle_error(self):
|
|
||||||
asynchat.async_chat.handle_error(self)
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def parse_request(self):
|
|
||||||
"""
|
|
||||||
Parse the next HTTP request start-line and message-headers.
|
|
||||||
HTTP/1.1 connections are persistent by default. If a client
|
|
||||||
requests a page, then idles (leaves the connection open),
|
|
||||||
then rfile.readline() will raise socket.error("timed out").
|
|
||||||
Note that it does this based on the value given to settimeout(),
|
|
||||||
and doesn't need the client to request or acknowledge the close
|
|
||||||
(although your TCP stack might suffer for it: cf Apache's history
|
|
||||||
with FIN_WAIT_2).
|
|
||||||
"""
|
|
||||||
request_line = self.rfile.readline()
|
|
||||||
if not request_line:
|
|
||||||
# Force self.ready = False so the connection will close.
|
|
||||||
self.ready = False
|
|
||||||
return
|
|
||||||
|
|
||||||
if request_line == RN:
|
|
||||||
# RFC 2616 sec 4.1: "...if the server is reading the protocol
|
|
||||||
# stream at the beginning of a message and receives a CRLF
|
|
||||||
# first, it should ignore the CRLF."
|
|
||||||
# But only ignore one leading line! else we enable a DoS.
|
|
||||||
request_line = self.rfile.readline()
|
|
||||||
if not request_line:
|
|
||||||
self.ready = False
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self.server
|
|
||||||
environ = self.environ
|
|
||||||
environ["SERVER_SOFTWARE"] = "%s WSGI Server" % server.version
|
|
||||||
|
|
||||||
method, path, req_protocol = request_line.strip().split(" ", 2)
|
|
||||||
environ["REQUEST_METHOD"] = method
|
|
||||||
|
|
||||||
# path may be an abs_path (including "http://host.domain.tld");
|
|
||||||
scheme, location, path, params, qs, frag = urlparse(path)
|
|
||||||
|
|
||||||
if frag:
|
|
||||||
self.simple_response("400 Bad Request",
|
|
||||||
"Illegal #fragment in Request-URI.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if scheme:
|
|
||||||
environ["wsgi.url_scheme"] = scheme
|
|
||||||
if params:
|
|
||||||
path = path + ";" + params
|
|
||||||
|
|
||||||
# Unquote the path+params (e.g. "/this%20path" -> "this path").
|
|
||||||
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
|
||||||
#
|
|
||||||
# But note that "...a URI must be separated into its components
|
|
||||||
# before the escaped characters within those components can be
|
|
||||||
# safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
|
|
||||||
atoms = [unquote(x) for x in QUOTED_SLASH.split(path)]
|
|
||||||
path = "%2F".join(atoms)
|
|
||||||
|
|
||||||
environ["SCRIPT_NAME"] = ""
|
|
||||||
environ["PATH_INFO"] = path
|
|
||||||
##if path == "*":
|
|
||||||
## # This means, of course, that the last wsgi_app (shortest path)
|
|
||||||
## # will always handle a URI of "*".
|
|
||||||
## environ["SCRIPT_NAME"] = ""
|
|
||||||
## environ["PATH_INFO"] = "*"
|
|
||||||
## self.wsgi_app = server.mount_points[-1][1]
|
|
||||||
##else:
|
|
||||||
## for mount_point, wsgi_app in server.mount_points:
|
|
||||||
## # The mount_points list should be sorted by length, descending.
|
|
||||||
## if path.startswith(mount_point + "/") or path == mount_point:
|
|
||||||
## environ["SCRIPT_NAME"] = mount_point
|
|
||||||
## environ["PATH_INFO"] = path[len(mount_point):]
|
|
||||||
## self.wsgi_app = wsgi_app
|
|
||||||
## break
|
|
||||||
## else:
|
|
||||||
## self.simple_response("404 Not Found")
|
|
||||||
## return
|
|
||||||
|
|
||||||
# Note that, like wsgiref and most other WSGI servers,
|
|
||||||
# we unquote the path but not the query string.
|
|
||||||
environ["QUERY_STRING"] = qs
|
|
||||||
|
|
||||||
# Compare request and server HTTP protocol versions, in case our
|
|
||||||
# server does not support the requested protocol. Limit our output
|
|
||||||
# to min(req, server). We want the following output:
|
|
||||||
# request server actual written supported response
|
|
||||||
# protocol protocol response protocol feature set
|
|
||||||
# a 1.0 1.0 1.0 1.0
|
|
||||||
# b 1.0 1.1 1.1 1.0
|
|
||||||
# c 1.1 1.0 1.0 1.0
|
|
||||||
# d 1.1 1.1 1.1 1.1
|
|
||||||
# Notice that, in (b), the response will be "HTTP/1.1" even though
|
|
||||||
# the client only understands 1.0. RFC 2616 10.5.6 says we should
|
|
||||||
# only return 505 if the _major_ version is different.
|
|
||||||
rp = int(req_protocol[5]), int(req_protocol[7])
|
|
||||||
sp = int(server.protocol[5]), int(server.protocol[7])
|
|
||||||
if sp[0] != rp[0]:
|
|
||||||
self.simple_response("505 HTTP Version Not Supported")
|
|
||||||
return
|
|
||||||
# Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
|
|
||||||
environ["SERVER_PROTOCOL"] = req_protocol
|
|
||||||
# set a non-standard environ entry so the WSGI app can know what
|
|
||||||
# the *real* server protocol is (and what features to support).
|
|
||||||
# See http://www.faqs.org/rfcs/rfc2145.html.
|
|
||||||
environ["ACTUAL_SERVER_PROTOCOL"] = server.protocol
|
|
||||||
self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
|
|
||||||
|
|
||||||
# If the Request-URI was an absoluteURI, use its location atom.
|
|
||||||
if location:
|
|
||||||
environ["SERVER_NAME"] = location
|
|
||||||
|
|
||||||
# then all the http headers
|
|
||||||
try:
|
|
||||||
self.read_headers()
|
|
||||||
except ValueError, ex:
|
|
||||||
self.simple_response("400 Bad Request", repr(ex.args))
|
|
||||||
return
|
|
||||||
|
|
||||||
creds = environ.get("HTTP_AUTHORIZATION", "").split(" ", 1)
|
|
||||||
environ["AUTH_TYPE"] = creds[0]
|
|
||||||
if creds[0].lower() == 'basic':
|
|
||||||
user, pw = base64.decodestring(creds[1]).split(":", 1)
|
|
||||||
environ["REMOTE_USER"] = user
|
|
||||||
|
|
||||||
# Persistent connection support
|
|
||||||
if self.response_protocol == "HTTP/1.1":
|
|
||||||
if environ.get("HTTP_CONNECTION", "") == "close":
|
|
||||||
self.close_connection = True
|
|
||||||
else:
|
|
||||||
# HTTP/1.0
|
|
||||||
if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
|
|
||||||
self.close_connection = True
|
|
||||||
|
|
||||||
# Transfer-Encoding support
|
|
||||||
te = None
|
|
||||||
if self.response_protocol == "HTTP/1.1":
|
|
||||||
te = environ.get("HTTP_TRANSFER_ENCODING")
|
|
||||||
if te:
|
|
||||||
te = [x.strip().lower() for x in te.split(",") if x.strip()]
|
|
||||||
|
|
||||||
read_chunked = False
|
|
||||||
|
|
||||||
if te:
|
|
||||||
for enc in te:
|
|
||||||
if enc == "chunked":
|
|
||||||
read_chunked = True
|
|
||||||
else:
|
|
||||||
# Note that, even if we see "chunked", we must reject
|
|
||||||
# if there is an extension we don't recognize.
|
|
||||||
self.simple_response("501 Unimplemented")
|
|
||||||
self.close_connection = True
|
|
||||||
return
|
|
||||||
|
|
||||||
self.read_chunked = read_chunked
|
|
||||||
return
|
|
||||||
|
|
||||||
if read_chunked:
|
|
||||||
if not self.decode_chunked():
|
|
||||||
return
|
|
||||||
|
|
||||||
# From PEP 333:
|
|
||||||
# "Servers and gateways that implement HTTP 1.1 must provide
|
|
||||||
# transparent support for HTTP 1.1's "expect/continue" mechanism.
|
|
||||||
# This may be done in any of several ways:
|
|
||||||
# 1. Respond to requests containing an Expect: 100-continue request
|
|
||||||
# with an immediate "100 Continue" response, and proceed normally.
|
|
||||||
# 2. Proceed with the request normally, but provide the application
|
|
||||||
# with a wsgi.input stream that will send the "100 Continue"
|
|
||||||
# response if/when the application first attempts to read from
|
|
||||||
# the input stream. The read request must then remain blocked
|
|
||||||
# until the client responds.
|
|
||||||
# 3. Wait until the client decides that the server does not support
|
|
||||||
# expect/continue, and sends the request body on its own.
|
|
||||||
# (This is suboptimal, and is not recommended.)
|
|
||||||
#
|
|
||||||
# We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
|
|
||||||
# but it seems like it would be a big slowdown for such a rare case.
|
|
||||||
if environ.get("HTTP_EXPECT", "") == "100-continue":
|
|
||||||
self.simple_response(100)
|
|
||||||
|
|
||||||
self.ready = True
|
|
||||||
|
|
||||||
def new_header(self,k,v):
|
|
||||||
if k:
|
|
||||||
environ = self.environ
|
|
||||||
envname = 'HTTP_'+k
|
|
||||||
if k in COMMA_SEPARATED_HEADERS:
|
|
||||||
existing = environ.get(envname)
|
|
||||||
if existing:
|
|
||||||
v = ", ".join((existing, v))
|
|
||||||
environ[envname] = v
|
|
||||||
|
|
||||||
def read_headers(self):
|
|
||||||
"""Read header lines from the incoming stream."""
|
|
||||||
k = v = None
|
|
||||||
while True:
|
|
||||||
line = self.rfile.readline()
|
|
||||||
if not line or '\0' in line:
|
|
||||||
# No more data--illegal end of headers
|
|
||||||
raise ValueError("Illegal headers")
|
|
||||||
elif line == RN:
|
|
||||||
# Normal end of headers
|
|
||||||
self.new_header(k,v)
|
|
||||||
break
|
|
||||||
elif line[0] in ' \t':
|
|
||||||
v += line.strip()
|
|
||||||
else:
|
|
||||||
self.new_header(k,v)
|
|
||||||
k, v = line.split(":", 1)
|
|
||||||
k, v = k.strip().upper(), v.strip()
|
|
||||||
|
|
||||||
environ = self.environ
|
|
||||||
ct = environ.pop("HTTP_CONTENT_TYPE", None)
|
|
||||||
if ct:
|
|
||||||
environ["CONTENT_TYPE"] = ct
|
|
||||||
cl = environ.pop("HTTP_CONTENT_LENGTH", None)
|
|
||||||
if cl:
|
|
||||||
environ["CONTENT_LENGTH"] = cl
|
|
||||||
|
|
||||||
def decode_chunked(self):
|
|
||||||
"""Decode the 'chunked' transfer coding."""
|
|
||||||
cl = 0
|
|
||||||
data = StringIO.StringIO()
|
|
||||||
while True:
|
|
||||||
line = self.rfile.readline().strip().split(";", 1)
|
|
||||||
chunk_size = int(line.pop(0), 16)
|
|
||||||
if chunk_size <= 0:
|
|
||||||
break
|
|
||||||
## if line: chunk_extension = line[0]
|
|
||||||
cl += chunk_size
|
|
||||||
data.write(self.rfile.read(chunk_size))
|
|
||||||
crlf = self.rfile.read(2)
|
|
||||||
if crlf != RN:
|
|
||||||
self.simple_response("400 Bad Request",
|
|
||||||
"Bad chunked transfer coding "
|
|
||||||
"(expected '\\r\\n', got %r)" % crlf)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Grab any trailer headers
|
|
||||||
self.read_headers()
|
|
||||||
|
|
||||||
data.seek(0)
|
|
||||||
self.environ["wsgi.input"] = data
|
|
||||||
self.environ["CONTENT_LENGTH"] = str(cl) or ""
|
|
||||||
return True
|
|
||||||
|
|
||||||
def respond(self):
|
|
||||||
"""
|
|
||||||
Call the appropriate WSGI app and write its iterable output.
|
|
||||||
"""
|
|
||||||
response = self.server.wsgi_app(self.environ, self.start_response)
|
|
||||||
try:
|
|
||||||
for chunk in response:
|
|
||||||
# "The start_response callable must not actually transmit
|
|
||||||
# the response headers. Instead, it must store them for the
|
|
||||||
# server or gateway to transmit only after the first
|
|
||||||
# iteration of the application return value that yields
|
|
||||||
# a NON-EMPTY string, or upon the application's first
|
|
||||||
# invocation of the write() callable." (PEP 333)
|
|
||||||
if chunk:
|
|
||||||
self.write(chunk)
|
|
||||||
finally:
|
|
||||||
if hasattr(response, "close"):
|
|
||||||
response.close()
|
|
||||||
|
|
||||||
if not self.sent_headers:
|
|
||||||
self.send_headers()
|
|
||||||
if self.chunked_write:
|
|
||||||
self.push("0\r\n")
|
|
||||||
|
|
||||||
def simple_response(self, status, msg=""):
|
|
||||||
"""Write a simple response back to the client."""
|
|
||||||
status = str(status)
|
|
||||||
buf = ["%s %s\r\n" % (self.server.protocol, status),
|
|
||||||
"Content-Length: %s\r\n" % len(msg)]
|
|
||||||
|
|
||||||
if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
|
|
||||||
# Request Entity Too Large
|
|
||||||
self.close_connection = True
|
|
||||||
buf.append("Connection: close\r\n")
|
|
||||||
|
|
||||||
buf.append(RN)
|
|
||||||
if msg:
|
|
||||||
buf.append(msg)
|
|
||||||
self.push(''.join(buf))
|
|
||||||
|
|
||||||
if self.close_connection or ( not self.server.keep_going ):
|
|
||||||
self.close_when_done()
|
|
||||||
else:
|
|
||||||
self.reset_when_done()
|
|
||||||
|
|
||||||
def start_response(self, status, headers, exc_info = None):
|
|
||||||
"""WSGI callable to begin the HTTP response."""
|
|
||||||
if self.started_response:
|
|
||||||
if not exc_info:
|
|
||||||
raise AssertionError("WSGI start_response called a second "
|
|
||||||
"time with no exc_info.")
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
raise exc_info[0], exc_info[1], exc_info[2]
|
|
||||||
finally:
|
|
||||||
exc_info = None
|
|
||||||
self.started_response = True
|
|
||||||
self.status = status
|
|
||||||
self.outheaders.extend(headers)
|
|
||||||
return self.write
|
|
||||||
|
|
||||||
def write(self, chunk):
|
|
||||||
"""
|
|
||||||
WSGI callable to write unbuffered data to the client.
|
|
||||||
|
|
||||||
This method is also used internally by start_response (to write
|
|
||||||
data from the iterable returned by the WSGI application).
|
|
||||||
"""
|
|
||||||
if not self.started_response:
|
|
||||||
raise AssertionError("WSGI write called before start_response.")
|
|
||||||
|
|
||||||
if not self.sent_headers:
|
|
||||||
self.send_headers()
|
|
||||||
|
|
||||||
if self.chunked_write and chunk:
|
|
||||||
buf = [hex(len(chunk))[2:], RN, chunk, RN]
|
|
||||||
self.push(''.join(buf))
|
|
||||||
else:
|
|
||||||
self.push(chunk)
|
|
||||||
|
|
||||||
def send_headers(self):
|
|
||||||
"""
|
|
||||||
Assert, process, and send the HTTP response message-headers.
|
|
||||||
"""
|
|
||||||
self.sent_headers = True
|
|
||||||
hkeys = [key.lower() for key, value in self.outheaders]
|
|
||||||
status = int(self.status[:3])
|
|
||||||
|
|
||||||
if status == 413:
|
|
||||||
# Request Entity Too Large. Close conn to avoid garbage.
|
|
||||||
self.close_connection = True
|
|
||||||
elif "content-length" not in hkeys:
|
|
||||||
# "All 1xx (informational), 204 (no content),
|
|
||||||
# and 304 (not modified) responses MUST NOT
|
|
||||||
# include a message-body." So no point chunking.
|
|
||||||
if status < 200 or status in (204, 205, 304):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if self.response_protocol == 'HTTP/1.1':
|
|
||||||
# Use the chunked transfer-coding
|
|
||||||
self.chunked_write = True
|
|
||||||
self.outheaders.append(("Transfer-Encoding", "chunked"))
|
|
||||||
else:
|
|
||||||
# Closing the conn is the only way to determine len.
|
|
||||||
self.close_connection = True
|
|
||||||
|
|
||||||
if "connection" not in hkeys:
|
|
||||||
if self.response_protocol == 'HTTP/1.1':
|
|
||||||
if self.close_connection:
|
|
||||||
self.outheaders.append(("Connection", "close"))
|
|
||||||
else:
|
|
||||||
if not self.close_connection:
|
|
||||||
self.outheaders.append(("Connection", "Keep-Alive"))
|
|
||||||
|
|
||||||
if "date" not in hkeys:
|
|
||||||
self.outheaders.append(("Date", rfc822.formatdate()))
|
|
||||||
|
|
||||||
server = self.server
|
|
||||||
|
|
||||||
if "server" not in hkeys:
|
|
||||||
self.outheaders.append(("Server", server.version))
|
|
||||||
|
|
||||||
buf = [server.protocol, " ", self.status, RN]
|
|
||||||
try:
|
|
||||||
buf += [k + ": " + v + RN for k, v in self.outheaders]
|
|
||||||
except TypeError:
|
|
||||||
if not isinstance(k, str):
|
|
||||||
raise TypeError("WSGI response header key %r is not a string.")
|
|
||||||
if not isinstance(v, str):
|
|
||||||
raise TypeError("WSGI response header value %r is not a string.")
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
buf.append(RN)
|
|
||||||
self.push(''.join(buf))
|
|
||||||
|
|
||||||
|
|
||||||
class WSGIServer(asyncore.dispatcher):
|
|
||||||
version = "Asynwsgi Server/1.0 alpha"
|
|
||||||
protocol = "HTTP/1.1"
|
|
||||||
def __init__(self, bind_addr, wsgi_app, server_name=None):
|
|
||||||
asyncore.dispatcher.__init__ (self)
|
|
||||||
self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.set_reuse_addr()
|
|
||||||
self.bind(bind_addr)
|
|
||||||
self.listen(1024)
|
|
||||||
self.keep_going = True
|
|
||||||
self.wsgi_app = wsgi_app
|
|
||||||
|
|
||||||
if not server_name:
|
|
||||||
server_name = socket.gethostname()
|
|
||||||
self.server_name = server_name
|
|
||||||
|
|
||||||
def writable(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def readable(self):
|
|
||||||
return self.accepting
|
|
||||||
|
|
||||||
def handle_accept(self):
|
|
||||||
try:
|
|
||||||
conn, addr = self.accept()
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
RequestHandler(conn, self)
|
|
||||||
|
|
||||||
def reload(self, signum, frame):
|
|
||||||
print 'reloading...'
|
|
||||||
self.keep_going = False
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def stop(self, signum, frame):
|
|
||||||
asyncore.close_all()
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
signal.signal(signal.SIGTERM, self.stop)
|
|
||||||
signal.signal(signal.SIGINT, self.stop)
|
|
||||||
asyncore.loop(timeout=0.1, use_poll=False)
|
|
||||||
|
|
||||||
def demo_app(environ, start_response):
|
|
||||||
write = start_response('200 OK', [('content-type', 'text/html')])
|
|
||||||
return ["<h1>Hello World!</h1>", "<br />%s"%time.ctime()]
|
|
||||||
|
|
||||||
def test_client(address='127.0.0.1:8000'):
|
|
||||||
time.sleep(3)
|
|
||||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
ip,port = address.split(':',1)
|
|
||||||
server.connect((ip,int(port)))
|
|
||||||
server.send('GET /\r\n\r\n')
|
|
||||||
while True:
|
|
||||||
sys.stdout.write(server.recv(1))
|
|
||||||
sys.stdout.write('CLOSE\n')
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
#thread.start_new_thread(test_client,())
|
|
||||||
#thread.start_new_thread(test_client,())
|
|
||||||
#thread.start_new_thread(test_client,())
|
|
||||||
WSGIServer(('127.0.0.1', 8000), demo_app).start()
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import time
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
N = 100000
|
|
||||||
r = re.compile('^(\S+)\s*\:\s*(.*?)\s*$')
|
|
||||||
|
|
||||||
a = "hello : world\r\n"
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
for k in xrange(N):
|
|
||||||
items = a.split(':',1)
|
|
||||||
x,y = items[0].strip(),items[1].strip()
|
|
||||||
print (time.time()-t0)/N
|
|
||||||
|
|
||||||
from gluon.utils import fast_urandom16
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
for k in xrange(N):
|
|
||||||
x,y = a.split(':',1)
|
|
||||||
x,y = x.strip(), y.strip()
|
|
||||||
print (time.time()-t0)/N
|
|
||||||
print x,y
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import os
|
|
||||||
import time
|
|
||||||
N = 100000
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
for k in xrange(N):
|
|
||||||
os.urandom(16)
|
|
||||||
print (time.time()-t0)/N
|
|
||||||
|
|
||||||
from gluon.utils import fast_urandom16
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
for k in xrange(N):
|
|
||||||
fast_urandom16()
|
|
||||||
print (time.time()-t0)/N
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
db =DAL()
|
|
||||||
db.define_table('person',Field('name'))
|
|
||||||
|
|
||||||
from gluon.dal import Expression
|
|
||||||
def IF(a,b,c,t=None):
|
|
||||||
db,f = a.db, a.db._adapter.expand
|
|
||||||
def r(x,represent=db._adapter.represent):
|
|
||||||
if x is None: return 'NULL'
|
|
||||||
elif isinstance(x,Expression): return str(x)
|
|
||||||
types = {type(True): 'boolean',
|
|
||||||
type(0): 'integer',
|
|
||||||
type(1.0): 'double'}
|
|
||||||
return represent(x,types.get(type(x),'string'))
|
|
||||||
return Expression(db,'CASE WHEN %s THEN %s ELSE %s END' % (f(a),r(b),r(c)))
|
|
||||||
|
|
||||||
db.person.insert(name='x')
|
|
||||||
db.person.insert(name='y')
|
|
||||||
db.person.insert(name='z')
|
|
||||||
print db().select(db.person.ALL, (db.person.name=='x').case('A',(db.person.name=='y').case('B','C')))
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import re, sys
|
|
||||||
|
|
||||||
regex = re.compile('\w+\.\w+')
|
|
||||||
|
|
||||||
for line in open(sys.argv[1]).read().split(' def '):
|
|
||||||
function = line.split('(',1)[0]
|
|
||||||
links = regex.findall(line)
|
|
||||||
m = {}
|
|
||||||
for link in links: m[link]=m.get(link,0)+1
|
|
||||||
print function
|
|
||||||
for link, count in sorted([(v,k) for v,k in m.iteritems()]):
|
|
||||||
if count>1:
|
|
||||||
print ' ',link, count
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
CACHED_REGEXES = {}
|
|
||||||
|
|
||||||
def re_compile(regex):
|
|
||||||
try:
|
|
||||||
return CACHED_REGEXES[regex]
|
|
||||||
except KeyError:
|
|
||||||
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
|
||||||
return compiled_regex
|
|
||||||
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
import re
|
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
|
|
||||||
class W2POpener(object):
|
|
||||||
regex = re.compile('\<input name\="_formkey" type\="hidden" value\="(?P<formkey>.+?)" \/\>\<input name\="_formname" type\="hidden" value\="(?P<formname>.+?)" \/\>')
|
|
||||||
|
|
||||||
def __init__(self,app=''):
|
|
||||||
self.app = app
|
|
||||||
self.cookies = {}
|
|
||||||
|
|
||||||
def get(self,url,cookies=None,headers=None,auth=None):
|
|
||||||
return self.post(url,data=None,cookies=cookies,headers=headers)
|
|
||||||
|
|
||||||
def post(self,url,data=None,cookies=None,headers=None,auth=None):
|
|
||||||
self.url = self.app+url
|
|
||||||
if cookies is None: cookies = self.cookies
|
|
||||||
if auth:
|
|
||||||
auth_handler = urllib2.HTTPBasicAuthHandler()
|
|
||||||
auth_handler.add_password(**auth)
|
|
||||||
opener = urllib2.build_opener(auth_handler)
|
|
||||||
else:
|
|
||||||
opener = urllib2.build_opener()
|
|
||||||
headers_list = []
|
|
||||||
for key,value in (headers or {}).iteritems():
|
|
||||||
if isinstance(value,(list,tuple)):
|
|
||||||
for v in value: headers_list.append((key,v))
|
|
||||||
else:
|
|
||||||
headers_list.append((key,value))
|
|
||||||
for key,value in (cookies or {}).iteritems():
|
|
||||||
headers_list.append(('Cookie','%s=%s' % (key,value)))
|
|
||||||
for key,value in headers_list:
|
|
||||||
opener.addheaders.append((key,str(value)))
|
|
||||||
if data is not None:
|
|
||||||
# if there is only one form, set _formname automatically
|
|
||||||
if not '_formname' in data and len(self.forms)==1:
|
|
||||||
data['_formname'] = self.forms.keys()[0]
|
|
||||||
# if there is no formkey but it is known, set it
|
|
||||||
if '_formname' in data and not '_formkey' in data and \
|
|
||||||
data['_formname'] in self.forms:
|
|
||||||
data['_formkey'] = self.forms[data['_formname']]
|
|
||||||
data = urllib.urlencode(data)
|
|
||||||
self.request = opener.open(self.url,data)
|
|
||||||
else:
|
|
||||||
self.request = opener.open(self.url)
|
|
||||||
self.status = self.request.getcode()
|
|
||||||
self.text = self.request.read()
|
|
||||||
self.headers = dict(self.request.headers)
|
|
||||||
self.cookies = dict(item[:item.find(';')].split('=') for item in \
|
|
||||||
self.headers.get('set-cookie','').split(','))
|
|
||||||
|
|
||||||
self.forms = {}
|
|
||||||
for match in W2POpener.regex.finditer(self.text):
|
|
||||||
self.forms[match.group('formname')] = match.group('formkey')
|
|
||||||
|
|
||||||
def test_registration_and_login():
|
|
||||||
session = W2POpener('http://127.0.0.1:8000/welcome/default/')
|
|
||||||
session.get('user/register')
|
|
||||||
data = dict(first_name = 'Homer',
|
|
||||||
last_name = 'Simpson',
|
|
||||||
email = 'homer@web2py.com',
|
|
||||||
password = 'test',
|
|
||||||
password_two = 'test',
|
|
||||||
_formname = 'register')
|
|
||||||
session.post('user/register',data = data)
|
|
||||||
|
|
||||||
session.get('user/login')
|
|
||||||
data = dict(email='homer@web2py.com',
|
|
||||||
password='test',
|
|
||||||
_formname = 'login')
|
|
||||||
session.post('user/login',data = data)
|
|
||||||
|
|
||||||
session.get('index')
|
|
||||||
assert 'Welcome Homer' in session.text
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test_registration_and_login()
|
|
||||||
|
|
||||||
-165
@@ -1,165 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import sys, os, time, atexit, signal, subprocess
|
|
||||||
|
|
||||||
class Daemon:
|
|
||||||
"""
|
|
||||||
A generic daemon class.
|
|
||||||
Usage: subclass the Daemon class and override the run() method
|
|
||||||
From: http://bit.ly/TnPxwp
|
|
||||||
Developed by Sander Marechal
|
|
||||||
Minor modifications by Massimo Di Pierro
|
|
||||||
"""
|
|
||||||
def __init__(self,
|
|
||||||
pidfile,
|
|
||||||
stdin='/dev/null',
|
|
||||||
stdout='/dev/null',
|
|
||||||
stderr=None):
|
|
||||||
|
|
||||||
self.stdin = stdin
|
|
||||||
self.stdout = stdout
|
|
||||||
self.stderr = stderr
|
|
||||||
self.pidfile = pidfile
|
|
||||||
|
|
||||||
def daemonize(self):
|
|
||||||
"""
|
|
||||||
do the UNIX double-fork magic, see Stevens
|
|
||||||
"Advanced Programming in the UNIX Environment"
|
|
||||||
for details (ISBN 0201563177)
|
|
||||||
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
pid = os.fork()
|
|
||||||
if pid > 0:
|
|
||||||
# exit first parent
|
|
||||||
sys.exit(0)
|
|
||||||
except OSError, e:
|
|
||||||
sys.stderr.write("fork #1 failed: %d (%s)\n" % (
|
|
||||||
e.errno, e.strerror))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# decouple from parent environment
|
|
||||||
os.chdir("/")
|
|
||||||
os.setsid()
|
|
||||||
os.umask(0)
|
|
||||||
|
|
||||||
# do second fork
|
|
||||||
try:
|
|
||||||
pid = os.fork()
|
|
||||||
if pid > 0:
|
|
||||||
# exit from second parent
|
|
||||||
sys.exit(0)
|
|
||||||
except OSError, e:
|
|
||||||
sys.stderr.write("fork #2 failed: %d (%s)\n" % (
|
|
||||||
e.errno, e.strerror))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# redirect standard file descriptors
|
|
||||||
sys.stdout.flush()
|
|
||||||
sys.stderr.flush()
|
|
||||||
if self.stdin != '/dev/null':
|
|
||||||
os.mkfifo(self.stdin)
|
|
||||||
si = open(self.stdin, 'r')
|
|
||||||
if self.stdout != '/dev/null':
|
|
||||||
os.mkfifo(self.stdout)
|
|
||||||
so = open(self.stdout, 'a+')
|
|
||||||
if self.stderr is None:
|
|
||||||
se = so
|
|
||||||
else:
|
|
||||||
if self.stderr != '/dev/null':
|
|
||||||
os.mkfifo(self.stderr)
|
|
||||||
se = open(self.stderr, 'a+', 0)
|
|
||||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
|
||||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
|
||||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
|
||||||
|
|
||||||
# write pidfile
|
|
||||||
# atexit.register(self.delpid)
|
|
||||||
pid = str(os.getpid())
|
|
||||||
open(self.pidfile,'w+').write("%s\n" % pid)
|
|
||||||
|
|
||||||
def delpid(self):
|
|
||||||
os.remove(self.pidfile)
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
"""
|
|
||||||
Start the daemon
|
|
||||||
"""
|
|
||||||
# Check for a pidfile to see if the daemon already runs
|
|
||||||
try:
|
|
||||||
pf = open(self.pidfile,'r')
|
|
||||||
pid = int(pf.read().strip())
|
|
||||||
pf.close()
|
|
||||||
except IOError:
|
|
||||||
pid = None
|
|
||||||
|
|
||||||
if pid:
|
|
||||||
message = "pidfile %s already exist. Daemon already running?\n"
|
|
||||||
sys.stderr.write(message % self.pidfile)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Start the daemon
|
|
||||||
self.daemonize()
|
|
||||||
self.run()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
"""
|
|
||||||
Stop the daemon
|
|
||||||
"""
|
|
||||||
# Get the pid from the pidfile
|
|
||||||
try:
|
|
||||||
pf = open(self.pidfile,'r')
|
|
||||||
pid = int(pf.read().strip())
|
|
||||||
pf.close()
|
|
||||||
except IOError:
|
|
||||||
pid = None
|
|
||||||
|
|
||||||
if not pid:
|
|
||||||
message = "pidfile %s does not exist. Daemon not running?\n"
|
|
||||||
sys.stderr.write(message % self.pidfile)
|
|
||||||
return # not an error in a restart
|
|
||||||
|
|
||||||
# Try killing the daemon process
|
|
||||||
try:
|
|
||||||
while 1:
|
|
||||||
os.kill(pid, signal.SIGTERM)
|
|
||||||
time.sleep(0.1)
|
|
||||||
except OSError, err:
|
|
||||||
err = str(err)
|
|
||||||
if err.find("No such process") > 0:
|
|
||||||
if os.path.exists(self.pidfile):
|
|
||||||
os.remove(self.pidfile)
|
|
||||||
else:
|
|
||||||
print str(err)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def restart(self):
|
|
||||||
"""
|
|
||||||
Restart the daemon
|
|
||||||
"""
|
|
||||||
self.stop()
|
|
||||||
self.start()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""
|
|
||||||
You should override this method when you subclass Daemon.
|
|
||||||
It will be called after the process has been
|
|
||||||
daemonized by start() or restart().
|
|
||||||
"""
|
|
||||||
if hasattr(self,'args'):
|
|
||||||
subprocess.call(self.args,
|
|
||||||
stdin=sys.stdin,
|
|
||||||
stdout=sys.stdout,
|
|
||||||
stderr=sys.stderr,
|
|
||||||
shell=True)
|
|
||||||
|
|
||||||
|
|
||||||
os.system('rm t1/*')
|
|
||||||
d = Daemon(
|
|
||||||
pidfile = '/Users/massimodipierro/Dropbox/web2py/temps/t1/process.pid',
|
|
||||||
stdin = '/Users/massimodipierro/Dropbox/web2py/temps/t1/fifo.in',
|
|
||||||
stdout = '/Users/massimodipierro/Dropbox/web2py/temps/t1/fifo.out',
|
|
||||||
stderr = None)
|
|
||||||
|
|
||||||
d.args = ['python looping.py']
|
|
||||||
d.start()
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
import sys
|
|
||||||
sys.path.append('/Users/massimodipierro/Dropbox/web2py/')
|
|
||||||
import pickle
|
|
||||||
from gluon import *
|
|
||||||
db = DAL()
|
|
||||||
print db
|
|
||||||
s = pickle.dumps(db)
|
|
||||||
db.close()
|
|
||||||
del db
|
|
||||||
|
|
||||||
a = pickle.loads(s)
|
|
||||||
print repr(a)
|
|
||||||
print str(a)
|
|
||||||
print BEAUTIFY(a).xml()
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import sys, os
|
|
||||||
import subprocess
|
|
||||||
import threading
|
|
||||||
import socket
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
def daemonize():
|
|
||||||
sys.stdout.flush()
|
|
||||||
sys.stderr.flush()
|
|
||||||
pid = os.fork()
|
|
||||||
if pid<0:
|
|
||||||
raise RuntimeError, "cannot fork"
|
|
||||||
elif pid>0:
|
|
||||||
(pid,status) = os.wait()
|
|
||||||
sys.exit(status)
|
|
||||||
os.chdir("/")
|
|
||||||
os.setsid()
|
|
||||||
os.umask(0)
|
|
||||||
pid = os.fork()
|
|
||||||
if pid<0:
|
|
||||||
raise RuntimeError, "cannot fork"
|
|
||||||
elif pid>0:
|
|
||||||
sys.exit(0)
|
|
||||||
os.dup2(os.open('/dev/null',os.O_RDONLY),sys.stdin.fileno())
|
|
||||||
os.dup2(os.open('/dev/null',os.O_WRONLY),sys.stdout.fileno())
|
|
||||||
os.dup2(os.open('/dev/null',os.O_WRONLY),sys.stderr.fileno())
|
|
||||||
|
|
||||||
class SmokingDaemon(threading.Thread):
|
|
||||||
def __init__(self,
|
|
||||||
cmd,
|
|
||||||
path,
|
|
||||||
tempdir = None):
|
|
||||||
self.cmd = cmd
|
|
||||||
self.path = path
|
|
||||||
self.tempdir = tempdir or tempfile.mkdtemp()
|
|
||||||
self.fifo_in_name = os.path.join(self.tempdir,'in.fifo')
|
|
||||||
self.fifo_out_name = os.path.join(self.tempdir,'out.fifo')
|
|
||||||
self.fifo_err_name = os.path.join(self.tempdir,'err.fifo')
|
|
||||||
daemonize(path)
|
|
||||||
threading.Thread.__init__(self)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
try: os.unlink(self.fifo_in_name)
|
|
||||||
except: pass
|
|
||||||
try: os.unlink(self.fifo_out_name)
|
|
||||||
except: pass
|
|
||||||
os.mkfifo(self.fifo_in_name)
|
|
||||||
os.mkfifo(self.fifo_out_name)
|
|
||||||
fifo_in_read = os.fdopen(
|
|
||||||
os.open(self.fifo_in_name,os.O_RDONLY|os.O_NONBLOCK))
|
|
||||||
self.output = os.fdopen(
|
|
||||||
os.open(self.fifo_out_name,os.O_RDONLY|os.O_NONBLOCK))
|
|
||||||
self.input = open(self.fifo_in_name,'a+')
|
|
||||||
fifo_out_write = open(self.fifo_out_name,'a+')
|
|
||||||
process = subprocess.call(self.cmd,
|
|
||||||
shell=True,
|
|
||||||
stdin=fifo_in_read,
|
|
||||||
stdout=fifo_out_write,
|
|
||||||
stderr=fifo_out_write)
|
|
||||||
|
|
||||||
sd = SmokingDaemon('ls -l','fifo.in','fifo.out')
|
|
||||||
sd.start()
|
|
||||||
sd.server()
|
|
||||||
sd.join()
|
|
||||||
open(sd.output.read()
|
|
||||||
|
|
||||||
sd = SmokingDaemon(id)
|
|
||||||
sd.start(command)
|
|
||||||
sd.stop()
|
|
||||||
sd.kill()
|
|
||||||
sd.seek()
|
|
||||||
sd.read(bytes)
|
|
||||||
sd.readline()
|
|
||||||
sd.write('hello world')
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import sys, os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
def runCmd( cmd, fifo ):
|
|
||||||
try:
|
|
||||||
os.unlink(fifo)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
os.mkfifo( "out_fifo" )
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
fifo = os.fdopen( os.open( "out_fifo",
|
|
||||||
os.O_RDONLY | os.O_NONBLOCK ) )
|
|
||||||
|
|
||||||
newcmd = "( %s ) 1>out_fifo 2>&1"%( cmd, )
|
|
||||||
|
|
||||||
process = subprocess.Popen( newcmd, shell = True,
|
|
||||||
stdout = subprocess.PIPE,
|
|
||||||
stderr = subprocess.STDOUT )
|
|
||||||
|
|
||||||
_localLog.debug( "Running: %s"%( cmd, ) )
|
|
||||||
|
|
||||||
while process.returncode == None:
|
|
||||||
# None means process is still running
|
|
||||||
|
|
||||||
# need to poll the process once so the returncode
|
|
||||||
# gets set (see docs)
|
|
||||||
process.poll()
|
|
||||||
|
|
||||||
try:
|
|
||||||
line = fifo.readline().strip()
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if line:
|
|
||||||
log.info( line )
|
|
||||||
|
|
||||||
remaining = fifo.read()
|
|
||||||
|
|
||||||
if remaining:
|
|
||||||
for line in [ line
|
|
||||||
for line in remaining.split( "\n" )
|
|
||||||
if line.strip() ]:
|
|
||||||
log.info( line.strip() )
|
|
||||||
|
|
||||||
if process.returncode:
|
|
||||||
_localLog.critical( "Return Value: %s"%( process.returncode, ) )
|
|
||||||
else:
|
|
||||||
_localLog.debug( "Return Value: %s"%( process.returncode, ) )
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
os.unlink( "out_fifo" )
|
|
||||||
|
|
||||||
|
|
||||||
mainlog.debug( os.getcwd() )
|
|
||||||
|
|
||||||
print
|
|
||||||
runCmd( "echo 'bye'", mainlog )
|
|
||||||
|
|
||||||
print
|
|
||||||
runCmd( "/usr/bin/false", mainlog )
|
|
||||||
|
|
||||||
print
|
|
||||||
runCmd( "ls -l; sleep 5; echo 'hi!'; sleep 5; ls -l", mainlog )
|
|
||||||
|
|
||||||
print
|
|
||||||
runCmd( "this_should_not_exists", mainlog )
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import time
|
|
||||||
for t in range(1000):
|
|
||||||
print t
|
|
||||||
time.sleep(5)
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
text = """
|
|
||||||
[[https://groups.google.com/forum/?fromgroups#!forum/web2py/ https://groups.google.com/forum/?fromgroups#!forum/web2py/]]
|
|
||||||
"""
|
|
||||||
|
|
||||||
print MARKMIN(text).xml()
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
total 184
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 31 Aug 26 22:53 benchmark.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 379 Aug 28 17:31 check.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 220 Sep 2 12:08 compile_rotator.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 3135 Aug 29 17:20 cookies.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 4759 Sep 6 16:05 daemon.py
|
|
||||||
prw-r--r-- 1 massimodipierro staff 0 Sep 7 15:43 fifo.1
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 671 Sep 7 15:43 fofo.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 1612 Sep 7 15:39 fofo.py.old
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 663 Sep 7 15:42 fofo.py~
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 64 Sep 6 15:11 looping.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 0 Sep 7 15:43 out_fifo
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 1218 Sep 6 15:11 process.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 475 Sep 6 09:32 read.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 3487 Sep 7 15:02 runcmd.log
|
|
||||||
drwxr-xr-x 3 massimodipierro staff 102 Sep 6 16:04 t1
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 170 Aug 26 09:45 test1.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 270 Aug 26 10:43 test2.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 1434 Aug 28 18:51 test3.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 649 Aug 30 15:16 test7.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 507 Sep 2 16:41 test8.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 118 Aug 28 14:52 test_1.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 595 Aug 28 10:42 test_bruno.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 515 Aug 28 09:54 test_cache.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 304 Aug 28 14:19 test_dominc.py
|
|
||||||
-rw-r--r-- 1 massimodipierro staff 2859 Aug 31 10:17 test_jim.py
|
|
||||||
prw-r--r-- 1 massimodipierro staff 0 Sep 7 13:30 tmp.1
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from gluon.contrib.populate import populate
|
|
||||||
populate(db.auth_user,10)
|
|
||||||
print db(db.auth_user).select()
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
class Path(object):
|
|
||||||
def __init__(self,s='/',sep=os.path.sep):
|
|
||||||
self.sep = sep
|
|
||||||
self.s = s.split(sep)
|
|
||||||
def __str__(self):
|
|
||||||
return self.sep.join(self.s)
|
|
||||||
def __add__(self,other):
|
|
||||||
if other[0]=='':
|
|
||||||
return Path(other)
|
|
||||||
else:
|
|
||||||
return Path(str(self)+os.sep+str(other))
|
|
||||||
def __getitem__(self,i):
|
|
||||||
return self.s[i]
|
|
||||||
def __setitem__(self,i,v):
|
|
||||||
self.s[i] = v
|
|
||||||
def append(self,v):
|
|
||||||
self.s.append(v)
|
|
||||||
@property
|
|
||||||
def filename(self):
|
|
||||||
return self.s[-1]
|
|
||||||
@property
|
|
||||||
def folder(self):
|
|
||||||
return Path(self.sep.join(self.s[:-1]))
|
|
||||||
|
|
||||||
>>> path = Path('/this/is/an/example.png')
|
|
||||||
>>> print path[-1]
|
|
||||||
example.png
|
|
||||||
>>> print path.filename
|
|
||||||
example.png
|
|
||||||
>>> print path.folder
|
|
||||||
/this/is/an
|
|
||||||
>>> path[1]='that'
|
|
||||||
/that/is/an/example.png
|
|
||||||
>>> print path.folder + 'this'
|
|
||||||
/that/is/an/this
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from gluon.dal import PostgreSQLAdapter
|
|
||||||
db = DAL()
|
|
||||||
db.define_table('test',Field('name'))
|
|
||||||
db._adapter.close()
|
|
||||||
db._adapter = PostgreSQLAdapter(db,'postgres://a:b@example.com/demo',do_connect=False)
|
|
||||||
print db(db.test)._select()
|
|
||||||
-24
@@ -1,24 +0,0 @@
|
|||||||
import pickle
|
|
||||||
db=DAL()
|
|
||||||
db.define_table('person',Field('name'))
|
|
||||||
db.define_table('thing',Field('name'),Field('owner','reference person'))
|
|
||||||
id = db.person.insert(name='Tim')
|
|
||||||
db.thing.insert(name='chair',owner=id)
|
|
||||||
rows = db(db.person).select()
|
|
||||||
|
|
||||||
a = pickle.dumps(rows[0])
|
|
||||||
b = pickle.loads(a)
|
|
||||||
print b
|
|
||||||
print type(b)
|
|
||||||
print b.name
|
|
||||||
|
|
||||||
a = pickle.dumps(rows)
|
|
||||||
b = pickle.loads(a)
|
|
||||||
print b
|
|
||||||
print type(b)
|
|
||||||
print b.db == db
|
|
||||||
|
|
||||||
print b[0]['name']
|
|
||||||
print b.first().name
|
|
||||||
b.first().update_record(name='Max')
|
|
||||||
print b.first().thing.select()
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
class Process(object):
|
|
||||||
def __init__(self,path):
|
|
||||||
self.path = path
|
|
||||||
self.fifo_in_filename = os.path.join(self.path,'fifo.in')
|
|
||||||
self.fifo_out_filename = os.path.join(self.path,'fifo.out')
|
|
||||||
self.process_filename = os.path.join(self.path,'process.pickle')
|
|
||||||
if not os.path.exists(path):
|
|
||||||
os.mkdir(path)
|
|
||||||
def run(self,command):
|
|
||||||
if os.path.exists(self.fifo_in_filename):
|
|
||||||
os.unlink(self.fifo_in_filename)
|
|
||||||
if os.path.exists(self.fifo_out_filename):
|
|
||||||
os.unlink(self.fifo_out_filename)
|
|
||||||
fifo_in = os.mkfifo(self.fifo_in_filename)
|
|
||||||
fifo_out = os.mkfifo(self.fifo_out_filename)
|
|
||||||
s = subprocess.Popen(command, shell=True,
|
|
||||||
stdin=fifo_in,
|
|
||||||
stdout=fifo_out,
|
|
||||||
stderr=fifo_out,
|
|
||||||
close_fds=True)
|
|
||||||
pickle.dump(s,open(self.process_filename,'wb'))
|
|
||||||
def interact(self):
|
|
||||||
fifo_out = open(self.fifo_out_filename,'rb')
|
|
||||||
while True:
|
|
||||||
print 'x',fifo_out.read(1)
|
|
||||||
|
|
||||||
p = Process('t1').run('python looping.py')
|
|
||||||
q = Process('t1').interact()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import re
|
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
from BeautifulSoup import BeautifulSoup
|
|
||||||
|
|
||||||
page = urllib2.urlopen('http://www.telegraph.co.uk/technology/internet/9524681/Sir-Tim-Berners-Lee-accuses-government-of-draconian-internet-snooping.html')
|
|
||||||
soup = BeautifulSoup(page)
|
|
||||||
|
|
||||||
items = soup.findAll(['h1','h2','h3','h4','h5','h6','p'])
|
|
||||||
text = '\n'.join(''.join(item.findAll(text=True)) for item in items).encode('utf8')
|
|
||||||
text = re.sub('\s*\n\s*','\n',re.sub('[ \t]+',' ',text))
|
|
||||||
print text
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
INFO : 2012-09-07 15:02:00,230 : foo : test
|
|
||||||
DEBUG : 2012-09-07 15:02:00,231 : main : /Users/massimodipierro/Dropbox/web2py/temps
|
|
||||||
DEBUG : 2012-09-07 15:02:00,237 : runCmd : Running: echo 'bye'
|
|
||||||
INFO : 2012-09-07 15:02:00,242 : main : bye
|
|
||||||
DEBUG : 2012-09-07 15:02:00,244 : runCmd : Return Value: 0
|
|
||||||
DEBUG : 2012-09-07 15:02:00,251 : runCmd : Running: /usr/bin/false
|
|
||||||
CRITICAL : 2012-09-07 15:02:00,278 : runCmd : Return Value: 1
|
|
||||||
DEBUG : 2012-09-07 15:02:00,290 : runCmd : Running: ls -l; sleep 5; echo 'hi!'; sleep 5; ls -l
|
|
||||||
INFO : 2012-09-07 15:02:00,398 : main : total 176
|
|
||||||
INFO : 2012-09-07 15:02:00,401 : main : -rw-r--r-- 1 massimodipierro staff 31 Aug 26 22:53 benchmark.py
|
|
||||||
INFO : 2012-09-07 15:02:00,402 : main : -rw-r--r-- 1 massimodipierro staff 379 Aug 28 17:31 check.py
|
|
||||||
INFO : 2012-09-07 15:02:00,403 : main : -rw-r--r-- 1 massimodipierro staff 220 Sep 2 12:08 compile_rotator.py
|
|
||||||
INFO : 2012-09-07 15:02:00,403 : main : -rw-r--r-- 1 massimodipierro staff 3135 Aug 29 17:20 cookies.py
|
|
||||||
INFO : 2012-09-07 15:02:00,404 : main : -rw-r--r-- 1 massimodipierro staff 4759 Sep 6 16:05 daemon.py
|
|
||||||
INFO : 2012-09-07 15:02:00,404 : main : -rw-r--r-- 1 massimodipierro staff 2759 Sep 7 15:01 fofo.py
|
|
||||||
INFO : 2012-09-07 15:02:00,405 : main : -rw-r--r-- 1 massimodipierro staff 723 Sep 7 13:43 fofo.py~
|
|
||||||
INFO : 2012-09-07 15:02:00,405 : main : -rw-r--r-- 1 massimodipierro staff 64 Sep 6 15:11 looping.py
|
|
||||||
INFO : 2012-09-07 15:02:00,406 : main : prw-r--r-- 1 massimodipierro staff 0 Sep 7 15:02 out_fifo
|
|
||||||
INFO : 2012-09-07 15:02:00,408 : main : -rw-r--r-- 1 massimodipierro staff 1218 Sep 6 15:11 process.py
|
|
||||||
INFO : 2012-09-07 15:02:00,409 : main : -rw-r--r-- 1 massimodipierro staff 475 Sep 6 09:32 read.py
|
|
||||||
INFO : 2012-09-07 15:02:00,410 : main : -rw-r--r-- 1 massimodipierro staff 581 Sep 7 15:02 runcmd.log
|
|
||||||
INFO : 2012-09-07 15:02:00,410 : main : drwxr-xr-x 3 massimodipierro staff 102 Sep 6 16:04 t1
|
|
||||||
INFO : 2012-09-07 15:02:00,411 : main : -rw-r--r-- 1 massimodipierro staff 170 Aug 26 09:45 test1.py
|
|
||||||
INFO : 2012-09-07 15:02:00,412 : main : -rw-r--r-- 1 massimodipierro staff 270 Aug 26 10:43 test2.py
|
|
||||||
INFO : 2012-09-07 15:02:00,412 : main : -rw-r--r-- 1 massimodipierro staff 1434 Aug 28 18:51 test3.py
|
|
||||||
INFO : 2012-09-07 15:02:00,413 : main : -rw-r--r-- 1 massimodipierro staff 649 Aug 30 15:16 test7.py
|
|
||||||
INFO : 2012-09-07 15:02:00,413 : main : -rw-r--r-- 1 massimodipierro staff 507 Sep 2 16:41 test8.py
|
|
||||||
INFO : 2012-09-07 15:02:00,414 : main : -rw-r--r-- 1 massimodipierro staff 118 Aug 28 14:52 test_1.py
|
|
||||||
INFO : 2012-09-07 15:02:00,414 : main : -rw-r--r-- 1 massimodipierro staff 595 Aug 28 10:42 test_bruno.py
|
|
||||||
INFO : 2012-09-07 15:02:00,415 : main : -rw-r--r-- 1 massimodipierro staff 515 Aug 28 09:54 test_cache.py
|
|
||||||
INFO : 2012-09-07 15:02:00,415 : main : -rw-r--r-- 1 massimodipierro staff 304 Aug 28 14:19 test_dominc.py
|
|
||||||
INFO : 2012-09-07 15:02:00,416 : main : -rw-r--r-- 1 massimodipierro staff 2859 Aug 31 10:17 test_jim.py
|
|
||||||
INFO : 2012-09-07 15:02:00,416 : main : prw-r--r-- 1 massimodipierro staff 0 Sep 7 13:30 tmp.1
|
|
||||||
INFO : 2012-09-07 15:02:05,411 : main : hi!
|
|
||||||
-109
@@ -1,109 +0,0 @@
|
|||||||
import asyncore
|
|
||||||
import asynchat
|
|
||||||
import socket
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
import thread
|
|
||||||
import string
|
|
||||||
|
|
||||||
RN = '\r\n'
|
|
||||||
STATUS_READING_HEADERS = 0
|
|
||||||
STATUS_READING_BODY = 1
|
|
||||||
STATUS_SENDING_RESPONSE = 2
|
|
||||||
|
|
||||||
class http_request_handler(asynchat.async_chat):
|
|
||||||
|
|
||||||
def __init__(self, sock, addr, sessions, log):
|
|
||||||
asynchat.async_chat.__init__(self, sock=sock)
|
|
||||||
self.addr = addr
|
|
||||||
self.sessions = sessions
|
|
||||||
self.ibuffer = []
|
|
||||||
self.obuffer = ""
|
|
||||||
self.set_terminator(RN+RN)
|
|
||||||
self.reading_headers = True
|
|
||||||
self.handling = False
|
|
||||||
self.cgi_data = None
|
|
||||||
self.log = log
|
|
||||||
self.status = STATUS_READING_HEADERS
|
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
|
||||||
"""Buffer the data"""
|
|
||||||
self.ibuffer.append(data)
|
|
||||||
|
|
||||||
def parse_headers(self,data):
|
|
||||||
if '\0' in data:
|
|
||||||
|
|
||||||
first_line, headers = data.split(RM,1)
|
|
||||||
self.op, self.path_info = first_line.split(' ',1)
|
|
||||||
lines = headers.replace(RN+' ',' ').replace(RN+'\t',' ').split(RN)
|
|
||||||
items = [line.split(':',1) for line in lines.split(RN) if ':' in line]
|
|
||||||
self.headers = dict((item[0].upper(),item[1]) for item in items)
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def found_terminator(self):
|
|
||||||
if self.status==STATUS_READING_HEADERS:
|
|
||||||
self.parse_headers(string.join(self.ibuffer,'')+'\r\n')
|
|
||||||
self.ibuffer = []
|
|
||||||
if self.op.upper() == "POST":
|
|
||||||
clen = self.headers.getheader("content-length")
|
|
||||||
self.set_terminator(int(clen))
|
|
||||||
self.status=STATUS_READ_BODY
|
|
||||||
else:
|
|
||||||
self.status=STATUS_SEND_RESPONSE
|
|
||||||
elif self.status==STATUS_READ_BODY:
|
|
||||||
self.ibuffer
|
|
||||||
|
|
||||||
self.set_terminator(None)
|
|
||||||
for data in self.run_app():
|
|
||||||
self.push(data)
|
|
||||||
time.sleep(1)
|
|
||||||
self.close()
|
|
||||||
elif not self.handling:
|
|
||||||
self.set_terminator(None) # browsers sometimes over-send
|
|
||||||
self.cgi_data = parse(self.headers, "".join(self.ibuffer))
|
|
||||||
self.handling = True
|
|
||||||
self.ibuffer = []
|
|
||||||
self.handle_request()
|
|
||||||
|
|
||||||
def handle_write(self):
|
|
||||||
print 'handle_write', self.buffer
|
|
||||||
self.send(self.buffer)
|
|
||||||
self.buffer = ''
|
|
||||||
|
|
||||||
def run_app(self):
|
|
||||||
return ['200 OK\r\n\r\n','Hello\n','World\n','%s\n' % time.ctime()]
|
|
||||||
|
|
||||||
class HTTPServer(asyncore.dispatcher):
|
|
||||||
def __init__(self, host, port, app):
|
|
||||||
asyncore.dispatcher.__init__(self)
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.app = app
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.set_reuse_addr()
|
|
||||||
self.bind((host, port))
|
|
||||||
self.listen(20)
|
|
||||||
|
|
||||||
def handle_accept(self):
|
|
||||||
pair = self.accept()
|
|
||||||
if not pair is None:
|
|
||||||
sock, addr = pair
|
|
||||||
print 'Incoming connection from %s' % repr(addr)
|
|
||||||
handler = http_request_handler(sock, addr, SESSIONS, None)
|
|
||||||
handler.server = self
|
|
||||||
|
|
||||||
def test_client(address='127.0.0.1:8000'):
|
|
||||||
time.sleep(3)
|
|
||||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
ip,port = address.split(':',1)
|
|
||||||
server.connect((ip,int(port)))
|
|
||||||
server.send('GET /\r\n\r\nthis the body')
|
|
||||||
while True:
|
|
||||||
sys.stdout.write(server.recv(1))
|
|
||||||
sys.stdout.write('CLOSE\n')
|
|
||||||
|
|
||||||
thread.start_new_thread(test_client,())
|
|
||||||
thread.start_new_thread(test_client,())
|
|
||||||
thread.start_new_thread(test_client,())
|
|
||||||
server = HTTPServer('localhost', 8000, lambda e,r: ['data'])
|
|
||||||
asyncore.loop()
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import threading
|
|
||||||
|
|
||||||
class SingletonPool(object):
|
|
||||||
|
|
||||||
thread_local = threading.local
|
|
||||||
locker = threadling.RLock()
|
|
||||||
pool = dict()
|
|
||||||
|
|
||||||
def __new__(cls, uri, *args, **kwargs):
|
|
||||||
print 'in new'
|
|
||||||
if not hasattr(thread_local,'db_instances'):
|
|
||||||
thread_local.db_instances = {}
|
|
||||||
try:
|
|
||||||
instance = thread_local.db_instances[uri]
|
|
||||||
print 'found existing instance'
|
|
||||||
except KeyError:
|
|
||||||
instance = super(DAL, cls).__new__(cls, uri, *args, **kwargs)
|
|
||||||
thread_local.db_instances[uri] = instance
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def __init__(self,uri,*args, **kwargs):
|
|
||||||
print "INIT"
|
|
||||||
try:
|
|
||||||
self.uri
|
|
||||||
print 'have self.uri',self.uri
|
|
||||||
except:
|
|
||||||
self.uri = uri
|
|
||||||
|
|
||||||
db=DAL('test')
|
|
||||||
print 'here'
|
|
||||||
db=DAL('test')
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
regex_url = re.compile(r'''
|
|
||||||
(^( # (/a/c/f.e/s)
|
|
||||||
/(?P<a> [\w\s+]+ ) # /a=app
|
|
||||||
( # (/c.f.e/s)
|
|
||||||
/(?P<c> [\w\s+]+ ) # /a/c=controller
|
|
||||||
( # (/f.e/s)
|
|
||||||
/(?P<f> [\w\s+]+ ) # /a/c/f=function
|
|
||||||
( # (.e)
|
|
||||||
\.(?P<e> [\w\s+]+ ) # /a/c/f.e=extension
|
|
||||||
)?
|
|
||||||
( # (/s)
|
|
||||||
/(?P<r> # /a/c/f.e/r=raw_args
|
|
||||||
.*
|
|
||||||
)
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
/?$)
|
|
||||||
''', re.X)
|
|
||||||
|
|
||||||
import time
|
|
||||||
n=100000
|
|
||||||
path = '/app/static/f.e/filename'
|
|
||||||
t0=time.time()
|
|
||||||
for k in range(n):
|
|
||||||
m = regex_url.match(path)
|
|
||||||
m.group('a')
|
|
||||||
m.group('c')
|
|
||||||
m.group('f')
|
|
||||||
print (time.time()-t0)/n
|
|
||||||
|
|
||||||
t0=time.time()
|
|
||||||
for k in range(n):
|
|
||||||
m = path.split('/')
|
|
||||||
lm = len(m)
|
|
||||||
if lm==0: m.append('a')
|
|
||||||
if lm==1: m.append('c')
|
|
||||||
if lm==2: m.append('f')
|
|
||||||
print (time.time()-t0)/n
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
from gluon.storage import Storage as Storage
|
|
||||||
n=10000
|
|
||||||
import time
|
|
||||||
|
|
||||||
s = Storage()
|
|
||||||
t0 = time.time()
|
|
||||||
for k in range(n):
|
|
||||||
s.x = 1
|
|
||||||
y = s.x
|
|
||||||
print (time.time()-t0)/n
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
db=DAL()
|
|
||||||
db.define_table('person',Field('name'))
|
|
||||||
db.person.insert(name="max")
|
|
||||||
db.person.insert(name="max")
|
|
||||||
db.person.insert(name="max")
|
|
||||||
print db(db.person).select().xml(strict=True)
|
|
||||||
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
print db.person[1]
|
|
||||||
s = pickle.dumps(db.person[1])
|
|
||||||
print pickle.loads(s)
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# run with web2py.py -S welcome -N -R thisfile.py
|
|
||||||
import time
|
|
||||||
|
|
||||||
db=DAL()
|
|
||||||
db.define_table('test',Field('one'))
|
|
||||||
db(db.test).delete()
|
|
||||||
for k in range(1000):
|
|
||||||
db.test.insert(one='one')
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
n = 100
|
|
||||||
t0 = time.time()
|
|
||||||
for k in range(n):
|
|
||||||
y = db.test.one
|
|
||||||
print 'time to access field obj',(time.time()-t0)/n
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
for k in range(n):
|
|
||||||
rows = db(db.test).select(cacheable=False) # (*)
|
|
||||||
print 'time to select 1000 recods',(time.time()-t0)/n/1000
|
|
||||||
|
|
||||||
row = db(db.test).select().first()
|
|
||||||
t0 = time.time()
|
|
||||||
for k in range(n):
|
|
||||||
y = row.id
|
|
||||||
y = row.one
|
|
||||||
print 'time to access field values',(time.time()-t0)/n
|
|
||||||
|
|
||||||
"""
|
|
||||||
Results:
|
|
||||||
|
|
||||||
web2py 1.99.7
|
|
||||||
|
|
||||||
time to access field obj 5.068 (microseconds)
|
|
||||||
time to select 1000 recods 38.441 (microseconds)
|
|
||||||
time to access field values 7.710 (microseconds)
|
|
||||||
total time to access one field for each of 1000 records: 7748 (microseconds)
|
|
||||||
|
|
||||||
web2py 2.0
|
|
||||||
time to access field obj 0.579 (microseconds)
|
|
||||||
time to select 1000 recods 33.820 (microseconds)
|
|
||||||
time to access field values 0.338 (microseconds)
|
|
||||||
total time to access one field for each of 1000 records: 371 (microseconds)
|
|
||||||
|
|
||||||
web2py 2.0 w cacheable = True (*)
|
|
||||||
|
|
||||||
time to access field obj 0.579 (microseconds)
|
|
||||||
time to select 1000 recods 24.741 (microseconds)
|
|
||||||
time to access field values 0.300 (microseconds)
|
|
||||||
total time to access one field for each of 1000 records: 324 (microseconds)
|
|
||||||
|
|
||||||
(benhcmarks with SQLite on Mac Air and python 2.7)
|
|
||||||
"""
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
db=DAL()
|
|
||||||
db.define_table('Meet',Field('name'))
|
|
||||||
db.define_table('Team',Field('name'))
|
|
||||||
db.define_table('Participant_team',
|
|
||||||
Field('Meet',db.Meet),
|
|
||||||
Field('Team',db.Team))
|
|
||||||
|
|
||||||
a=db.Meet.insert(name='here')
|
|
||||||
b=db.Team.insert(name='snakes')
|
|
||||||
db.Participant_team.insert(Meet=a,Team=b)
|
|
||||||
teamStaff = db(db.Meet.id == a).select(
|
|
||||||
db.Meet.ALL, db.Team.ALL,
|
|
||||||
join = db.Team.on(
|
|
||||||
(db.Participant_team.Meet == db.Meet.id) &
|
|
||||||
(db.Participant_team.Team == db.Team.id)))
|
|
||||||
|
|
||||||
print teamStaff
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
db=DAL()
|
|
||||||
db.define_table('t',Field('a'))
|
|
||||||
db.t.insert(a='xxx')
|
|
||||||
rows = db(db.t).select()
|
|
||||||
import pickle
|
|
||||||
print pickle.loads(pickle.dumps(rows))
|
|
||||||
rows = db(db.t).select(cacheable=True)
|
|
||||||
s= pickle.dumps(rows)
|
|
||||||
print pickle.loads(s)
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
db = DAL(lazy_tables = True)
|
|
||||||
|
|
||||||
db.define_table('x',
|
|
||||||
Field('name', 'string')
|
|
||||||
)
|
|
||||||
|
|
||||||
db.define_table('y',
|
|
||||||
Field('x', 'reference x'),
|
|
||||||
Field('age', 'integer', default = 30)
|
|
||||||
)
|
|
||||||
|
|
||||||
x_id = db.x.insert(name = 'barry')
|
|
||||||
db.y.insert(x = x_id, age = 99)
|
|
||||||
|
|
||||||
x = db(db.x.id > 0).select().first()
|
|
||||||
for y in x.y.select():
|
|
||||||
print y
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
db=DAL()
|
|
||||||
db.define_table('test',Field('myid','id'),Field('name'))
|
|
||||||
db.test.insert(name='max')
|
|
||||||
row=db.test[1]
|
|
||||||
print row
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
db=DAL()
|
|
||||||
|
|
||||||
db.define_table("article",
|
|
||||||
Field("title"),
|
|
||||||
Field("slug"),
|
|
||||||
Field("number_of_views", "integer", default=0)
|
|
||||||
)
|
|
||||||
def printer(row):
|
|
||||||
print row
|
|
||||||
return True
|
|
||||||
db.article.slug.compute = lambda row: printer(row) and IS_SLUG()(row.title)[0]
|
|
||||||
|
|
||||||
|
|
||||||
article_id = db.article.insert(title='This is a Test')
|
|
||||||
row = db.article[article_id]
|
|
||||||
print 'xxx1'
|
|
||||||
print row.update_record(number_of_views=row.number_of_views + 1)
|
|
||||||
print row.update_record(number_of_views=row.number_of_views + 1)
|
|
||||||
print row.update_record(number_of_views=row.number_of_views + 1)
|
|
||||||
print 'xxx2'
|
|
||||||
print row
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import sys, time
|
|
||||||
sys.path.append('/Users/massimodipierro/Dropbox/web2py')
|
|
||||||
from gluon.cache import CacheOnDisk
|
|
||||||
from gluon.storage import Storage
|
|
||||||
request = Storage()
|
|
||||||
request.folder = '/Users/massimodipierro/Dropbox/web2py/applications/welcome'
|
|
||||||
c = CacheOnDisk(request)
|
|
||||||
hello = c('key',lambda:'hello',0)
|
|
||||||
print hello
|
|
||||||
hello = c('key',lambda:'world',None)
|
|
||||||
print hello
|
|
||||||
hello = c('key',lambda:'world',1)
|
|
||||||
print hello
|
|
||||||
time.sleep(2)
|
|
||||||
hello = c('key',lambda:'world',1)
|
|
||||||
print hello
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
db=DAL()
|
|
||||||
db.define_table('person',Field('name'))
|
|
||||||
id = db.person.insert(name="max")
|
|
||||||
assert(id.name=='max')
|
|
||||||
db.define_table('dog',Field('name'),Field('owner','reference person'))
|
|
||||||
db.dog.insert(name='skipper',owner=1)
|
|
||||||
row = db(db.person.id==db.dog.owner).select().first()
|
|
||||||
assert(row[db.person.name]=='max')
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import datetime
|
|
||||||
import os
|
|
||||||
|
|
||||||
db = DAL()
|
|
||||||
from gluon.tools import Auth
|
|
||||||
|
|
||||||
auth = Auth(db) # authentication/authorization
|
|
||||||
|
|
||||||
auth_user = db.define_table(
|
|
||||||
auth.settings.table_user_name,
|
|
||||||
Field('first_name', length=128, default='', required=True),
|
|
||||||
Field('last_name', length=128, default='', required=True),
|
|
||||||
Field('email', length=128, unique=True, required=True),
|
|
||||||
Field('password', 'password', length=512,
|
|
||||||
readable=True, writable=True, label='Password'),
|
|
||||||
Field('registration_key', length=512,
|
|
||||||
writable=False, readable=False, default=''),
|
|
||||||
Field('reset_password_key', length=512,
|
|
||||||
writable=False, readable=False, default=''),
|
|
||||||
Field('registration_id', length=512,
|
|
||||||
writable=False, readable=False, default=''),
|
|
||||||
Field('brillLogon', length=10, default='', label='Brill Logon'),
|
|
||||||
Field('technician', 'boolean', default=False),
|
|
||||||
Field('dispatcher', 'boolean', default=False),
|
|
||||||
Field('lastFirst', compute=lambda u: '%s, %s' % (u['last_name'], u['first_name']), label='Name'),
|
|
||||||
Field('firstLast', compute=lambda u: '%s %s' % (u['first_name'], u['last_name']), label='Name'),
|
|
||||||
format='%(last_name)s, %(first_name)s')
|
|
||||||
|
|
||||||
auth_user.first_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
|
||||||
auth_user.last_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
|
||||||
auth_user.password.requires = [CRYPT()]
|
|
||||||
auth_user.email.requires = [IS_EMAIL(error_message=auth.messages.invalid_email),
|
|
||||||
IS_NOT_IN_DB(db, auth_user.email),
|
|
||||||
IS_NOT_EMPTY(error_message=auth.messages.is_empty)]
|
|
||||||
auth_user.id.readable = False
|
|
||||||
auth_user._plural = 'Users'
|
|
||||||
|
|
||||||
auth.settings.table_user = auth_user
|
|
||||||
auth.define_tables() # creates all needed tables
|
|
||||||
|
|
||||||
warehouse = db.define_table('warehouse',
|
|
||||||
Field('warehouseId', 'id'),
|
|
||||||
Field('warehouseNumber', 'integer', required=True, unique=True, label='Warehouse #'),
|
|
||||||
|
|
||||||
Field('name', length=50, required=True, unique=True),
|
|
||||||
|
|
||||||
Field('allowPricesToFall', 'boolean', default=False,
|
|
||||||
label='Allow Prices to Fall'),
|
|
||||||
Field('hin', length=10),
|
|
||||||
Field('active', 'boolean', default=True),
|
|
||||||
format='%(warehouseNumber)s - %(name)s')
|
|
||||||
|
|
||||||
warehouse.warehouseNumber.requires = [IS_NOT_EMPTY(error_message=auth.messages.is_empty),
|
|
||||||
IS_NOT_IN_DB(db, warehouse.warehouseNumber)]
|
|
||||||
warehouse.name.requires = [IS_NOT_IN_DB(db, warehouse.name),
|
|
||||||
IS_NOT_EMPTY(error_message=auth.messages.is_empty)]
|
|
||||||
warehouse._plural = 'Warehouses'
|
|
||||||
|
|
||||||
|
|
||||||
link = db.define_table('link',
|
|
||||||
Field('linkId', 'id', readable=False),
|
|
||||||
Field('name', length=50, required=True, unique=True),
|
|
||||||
Field('parentLinkId', 'reference link', required=True,
|
|
||||||
label='Parent Link'),
|
|
||||||
Field('controller', length=512, required=True),
|
|
||||||
Field('method', length=512, required=True),
|
|
||||||
Field('picture', length=512, required=False),
|
|
||||||
Field('permissionId', db.auth_permission, label='Rqd Permission'),
|
|
||||||
Field('groupId', db.auth_group, label='Rqd Group'),
|
|
||||||
Field('description', 'text', required=True),
|
|
||||||
format='%(name)s')
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import os, time
|
|
||||||
from gluon.contrib.webclient import WebClient
|
|
||||||
|
|
||||||
s = WebClient('http://127.0.0.1:8000/test2/test/')
|
|
||||||
s.get('index')
|
|
||||||
print s.sessions
|
|
||||||
id = s.sessions['test2']
|
|
||||||
time.sleep(1)
|
|
||||||
#print os.path.getmtime(os.path.join('applications','test2','sessions',id))
|
|
||||||
s.get('index')
|
|
||||||
id = s.sessions['test2']
|
|
||||||
#print os.path.getmtime(os.path.join('applications','test2','sessions',id))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import copy
|
|
||||||
db =DAL()
|
|
||||||
db._adapter.types = copy.copy(db._adapter.types)
|
|
||||||
db._adapter.types['boolean']='INTEGER'
|
|
||||||
db._adapter.TRUE = 1
|
|
||||||
db._adapter.FALSE = 0
|
|
||||||
db.define_table('test',Field('b', 'boolean'))
|
|
||||||
db.test.insert(b=True)
|
|
||||||
db.test.insert(b=False)
|
|
||||||
rows = db(db.test).select()
|
|
||||||
print db.executesql(db(db.test)._select())
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import sys
|
|
||||||
sys.path.append('../')
|
|
||||||
from gluon.dal import DAL, THREAD_LOCAL
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
db =DAL()
|
|
||||||
s = pickle.dumps(db)
|
|
||||||
db.close()
|
|
||||||
a = pickle.loads(s)
|
|
||||||
print THREAD_LOCAL.db_instances, THREAD_LOCAL.db_instances_zombie
|
|
||||||
db =DAL()
|
|
||||||
print a is db
|
|
||||||
print THREAD_LOCAL.db_instances, THREAD_LOCAL.db_instances_zombie
|
|
||||||
b = pickle.loads(s)
|
|
||||||
print THREAD_LOCAL.db_instances, THREAD_LOCAL.db_instances_zombie
|
|
||||||
print a is b
|
|
||||||
c = DAL()
|
|
||||||
print a is c
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
Metadata-Version: 1.0
|
|
||||||
Name: web2py
|
|
||||||
Version: 2.1.1
|
|
||||||
Summary: full-stack framework for rapid development and prototyping
|
|
||||||
of secure database-driven web-based applications, written and
|
|
||||||
programmable in Python.
|
|
||||||
Home-page: http://web2py.com
|
|
||||||
Author: Massimo Di Pierro
|
|
||||||
Author-email: mdipierro@cs.depaul.edu
|
|
||||||
License: http://web2py.com/examples/default/license
|
|
||||||
Description:
|
|
||||||
Everything in one package with no dependencies. Development, deployment,
|
|
||||||
debugging, testing, database administration and maintenance of applications can
|
|
||||||
be done via the provided web interface. web2py has no configuration files,
|
|
||||||
requires no installation, can run off a USB drive. web2py uses Python for the
|
|
||||||
Model, the Views and the Controllers, has a built-in ticketing system to manage
|
|
||||||
errors, an internationalization engine, works with SQLite, PostgreSQL, MySQL,
|
|
||||||
MSSQL, FireBird, Oracle, IBM DB2, Informix, Ingres, sybase and Google App Engine via a
|
|
||||||
Database Abstraction Layer. web2py includes libraries to handle
|
|
||||||
HTML/XML, RSS, ATOM, CSV, RTF, JSON, AJAX, XMLRPC, WIKI markup. Production
|
|
||||||
ready, capable of upload/download streaming of very large files, and always
|
|
||||||
backward compatible.
|
|
||||||
|
|
||||||
Platform: Windows
|
|
||||||
Platform: Linux
|
|
||||||
Platform: Mac
|
|
||||||
Platform: Unix
|
|
||||||
Platform: Windows Mobile
|
|
||||||
Classifier: Development Status :: 5 - Production/Stable
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
LICENSE
|
|
||||||
MANIFEST.in
|
|
||||||
README
|
|
||||||
VERSION
|
|
||||||
setup.py
|
|
||||||
w2p_apps
|
|
||||||
w2p_clone
|
|
||||||
w2p_run
|
|
||||||
gluon/__init__.py
|
|
||||||
gluon/admin.py
|
|
||||||
gluon/cache.py
|
|
||||||
gluon/cfs.py
|
|
||||||
gluon/compileapp.py
|
|
||||||
gluon/contenttype.py
|
|
||||||
gluon/custom_import.py
|
|
||||||
gluon/dal.py
|
|
||||||
gluon/debug.py
|
|
||||||
gluon/decoder.py
|
|
||||||
gluon/fileutils.py
|
|
||||||
gluon/globals.py
|
|
||||||
gluon/highlight.py
|
|
||||||
gluon/html.py
|
|
||||||
gluon/http.py
|
|
||||||
gluon/import_all.py
|
|
||||||
gluon/languages.py
|
|
||||||
gluon/main.py
|
|
||||||
gluon/messageboxhandler.py
|
|
||||||
gluon/myregex.py
|
|
||||||
gluon/newcron.py
|
|
||||||
gluon/portalocker.py
|
|
||||||
gluon/reserved_sql_keywords.py
|
|
||||||
gluon/restricted.py
|
|
||||||
gluon/rewrite.py
|
|
||||||
gluon/rocket.py
|
|
||||||
gluon/sanitizer.py
|
|
||||||
gluon/scheduler.py
|
|
||||||
gluon/serializers.py
|
|
||||||
gluon/settings.py
|
|
||||||
gluon/shell.py
|
|
||||||
gluon/sql.py
|
|
||||||
gluon/sqlhtml.py
|
|
||||||
gluon/storage.py
|
|
||||||
gluon/streamer.py
|
|
||||||
gluon/template.py
|
|
||||||
gluon/tools.py
|
|
||||||
gluon/utf8.py
|
|
||||||
gluon/utils.py
|
|
||||||
gluon/validators.py
|
|
||||||
gluon/widget.py
|
|
||||||
gluon/winservice.py
|
|
||||||
gluon/xmlrpc.py
|
|
||||||
gluon/contrib/AuthorizeNet.py
|
|
||||||
gluon/contrib/DowCommerce.py
|
|
||||||
gluon/contrib/__init__.py
|
|
||||||
gluon/contrib/aes.py
|
|
||||||
gluon/contrib/autolinks.py
|
|
||||||
gluon/contrib/feedparser.py
|
|
||||||
gluon/contrib/gae_memcache.py
|
|
||||||
gluon/contrib/gae_retry.py
|
|
||||||
gluon/contrib/generics.py
|
|
||||||
gluon/contrib/google_wallet.py
|
|
||||||
gluon/contrib/gql.py
|
|
||||||
gluon/contrib/imageutils.py
|
|
||||||
gluon/contrib/memdb.py
|
|
||||||
gluon/contrib/pam.py
|
|
||||||
gluon/contrib/pbkdf2.py
|
|
||||||
gluon/contrib/populate.py
|
|
||||||
gluon/contrib/pyfpdf.py
|
|
||||||
gluon/contrib/qdb.py
|
|
||||||
gluon/contrib/redis_cache.py
|
|
||||||
gluon/contrib/redis_session.py
|
|
||||||
gluon/contrib/rss2.py
|
|
||||||
gluon/contrib/shell.py
|
|
||||||
gluon/contrib/simplejsonrpc.py
|
|
||||||
gluon/contrib/sms_utils.py
|
|
||||||
gluon/contrib/spreadsheet.py
|
|
||||||
gluon/contrib/stripe.py
|
|
||||||
gluon/contrib/taskbar_widget.py
|
|
||||||
gluon/contrib/timecollect.py
|
|
||||||
gluon/contrib/user_agent_parser.py
|
|
||||||
gluon/contrib/webclient.py
|
|
||||||
gluon/contrib/websocket_messaging.py
|
|
||||||
gluon/contrib/fpdf/__init__.py
|
|
||||||
gluon/contrib/fpdf/fonts.py
|
|
||||||
gluon/contrib/fpdf/fpdf.py
|
|
||||||
gluon/contrib/fpdf/html.py
|
|
||||||
gluon/contrib/fpdf/php.py
|
|
||||||
gluon/contrib/fpdf/template.py
|
|
||||||
gluon/contrib/fpdf/ttfonts.py
|
|
||||||
gluon/contrib/gateways/__init__.py
|
|
||||||
gluon/contrib/gateways/fcgi.py
|
|
||||||
gluon/contrib/login_methods/__init__.py
|
|
||||||
gluon/contrib/login_methods/basic_auth.py
|
|
||||||
gluon/contrib/login_methods/browserid_account.py
|
|
||||||
gluon/contrib/login_methods/cas_auth.py
|
|
||||||
gluon/contrib/login_methods/dropbox_account.py
|
|
||||||
gluon/contrib/login_methods/email_auth.py
|
|
||||||
gluon/contrib/login_methods/extended_login_form.py
|
|
||||||
gluon/contrib/login_methods/gae_google_account.py
|
|
||||||
gluon/contrib/login_methods/ldap_auth.py
|
|
||||||
gluon/contrib/login_methods/linkedin_account.py
|
|
||||||
gluon/contrib/login_methods/loginza.py
|
|
||||||
gluon/contrib/login_methods/motp_auth.py
|
|
||||||
gluon/contrib/login_methods/oauth10a_account.py
|
|
||||||
gluon/contrib/login_methods/oauth20_account.py
|
|
||||||
gluon/contrib/login_methods/openid_auth.py
|
|
||||||
gluon/contrib/login_methods/pam_auth.py
|
|
||||||
gluon/contrib/login_methods/rpx_account.py
|
|
||||||
gluon/contrib/login_methods/x509_auth.py
|
|
||||||
gluon/contrib/markdown/__init__.py
|
|
||||||
gluon/contrib/markdown/markdown2.py
|
|
||||||
gluon/contrib/markmin/__init__.py
|
|
||||||
gluon/contrib/markmin/markmin2html.py
|
|
||||||
gluon/contrib/markmin/markmin2latex.py
|
|
||||||
gluon/contrib/markmin/markmin2pdf.py
|
|
||||||
gluon/contrib/memcache/__init__.py
|
|
||||||
gluon/contrib/memcache/memcache.py
|
|
||||||
gluon/contrib/pymysql/__init__.py
|
|
||||||
gluon/contrib/pymysql/charset.py
|
|
||||||
gluon/contrib/pymysql/connections.py
|
|
||||||
gluon/contrib/pymysql/converters.py
|
|
||||||
gluon/contrib/pymysql/cursors.py
|
|
||||||
gluon/contrib/pymysql/err.py
|
|
||||||
gluon/contrib/pymysql/times.py
|
|
||||||
gluon/contrib/pymysql/util.py
|
|
||||||
gluon/contrib/pyrtf/Constants.py
|
|
||||||
gluon/contrib/pyrtf/Elements.py
|
|
||||||
gluon/contrib/pyrtf/PropertySets.py
|
|
||||||
gluon/contrib/pyrtf/Renderer.py
|
|
||||||
gluon/contrib/pyrtf/Styles.py
|
|
||||||
gluon/contrib/pyrtf/__init__.py
|
|
||||||
gluon/contrib/pysimplesoap/__init__.py
|
|
||||||
gluon/contrib/pysimplesoap/client.py
|
|
||||||
gluon/contrib/pysimplesoap/server.py
|
|
||||||
gluon/contrib/pysimplesoap/simplexml.py
|
|
||||||
gluon/contrib/pysimplesoap/transport.py
|
|
||||||
gluon/contrib/simplejson/__init__.py
|
|
||||||
gluon/contrib/simplejson/decoder.py
|
|
||||||
gluon/contrib/simplejson/encoder.py
|
|
||||||
gluon/contrib/simplejson/ordered_dict.py
|
|
||||||
gluon/contrib/simplejson/scanner.py
|
|
||||||
gluon/contrib/simplejson/tool.py
|
|
||||||
gluon/tests/__init__.py
|
|
||||||
gluon/tests/test_cache.py
|
|
||||||
gluon/tests/test_contribs.py
|
|
||||||
gluon/tests/test_dal.py
|
|
||||||
gluon/tests/test_html.py
|
|
||||||
gluon/tests/test_is_url.py
|
|
||||||
gluon/tests/test_languages.py
|
|
||||||
gluon/tests/test_markmin.py
|
|
||||||
gluon/tests/test_router.py
|
|
||||||
gluon/tests/test_routes.py
|
|
||||||
gluon/tests/test_storage.py
|
|
||||||
gluon/tests/test_template.py
|
|
||||||
gluon/tests/test_utils.py
|
|
||||||
gluon/tests/test_web.py
|
|
||||||
web2py.egg-info/PKG-INFO
|
|
||||||
web2py.egg-info/SOURCES.txt
|
|
||||||
web2py.egg-info/dependency_links.txt
|
|
||||||
web2py.egg-info/top_level.txt
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
gluon/contrib/gateways
|
|
||||||
gluon/contrib/markmin
|
|
||||||
gluon/contrib/markdown
|
|
||||||
gluon/contrib/pyrtf
|
|
||||||
gluon/contrib/pymysql
|
|
||||||
gluon/contrib/fpdf
|
|
||||||
gluon
|
|
||||||
gluon/contrib
|
|
||||||
gluon/tests
|
|
||||||
gluon/contrib/login_methods
|
|
||||||
gluon/contrib/pysimplesoap
|
|
||||||
gluon/contrib/simplejson
|
|
||||||
gluon/contrib/memcache
|
|
||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user