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