Package shttp :: Module http
[hide private]
[frames] | no frames]

Source Code for Module shttp.http

  1  import os 
  2  import sys 
  3  import shutil 
  4  import socket 
  5  import SocketServer 
  6  from SocketServer import BaseServer, ThreadingTCPServer, TCPServer 
  7  import mimetypes 
  8  mimetypes.init() 
  9  from BaseHTTPServer import HTTPServer as httpbase 
 10  from CGIHTTPServer import CGIHTTPRequestHandler, nobody_uid 
 11  try: 
 12      from OpenSSL import SSL 
 13  except ImportError: 
 14      import warn 
 15      warn.debug("Unable to use the HTTPS protocol") 
 16      SSL = None 
 17  try: 
 18      from cStringIO  import StringIO 
 19  except ImportError: 
 20      from StringIO import StringIO 
 21  import warn 
 22  import urllib 
 23  import select 
 24  import urlparse 
 25  import posixpath 
 26  import re 
 27  import cgi 
 28  import types 
 29  import thread 
 30  import gzip 
 31  __thread_data__ = {} 
 32   
33 -def getrequest():
34 """ Returns the spyro's request dictionary that 35 rules the current thread or shttp.http request. If this thread is not 36 ruled by an http request, it will raise a KeyError exception""" 37 return __thread_data__[thread.get_ident()][0]
38
39 -def getthreaddata():
40 return __thread_data__[thread.get_ident()]
41
42 -def setheader(header):
43 __thread_data__[thread.get_ident()][1].append(header)
44
45 -def _setrequest(data):
46 headers = [] 47 __thread_data__[thread.get_ident()] = [data, headers]
48
49 -def _delrequest():
50 del __thread_data__[thread.get_ident()]
51 52 warn = warn.Warn("shttp.http") 53
54 -class CustomResponse:
55 - def __init__(self, data, headers={}, content_type='text/plain', status=200, reason="Response Follows", options={}, content_type_from_path=None):
56 """ This class is used as an exception to send Custom Responses from a 57 SPyRO method to the HTTP web server. The web server must known how this 58 must be handled. 59 |data| The data to be send in the response (an str object) 60 |headers| A dictionary with pair valued headers 61 |content_type| The content type of the data 62 |status| The number of status to present in the response (if it's posible). 63 The default value is 200 (OK). 64 """ 65 self.reason = reason 66 self.options = options 67 self.status = status 68 self.data = data 69 self.headers = headers 70 self.content_type_from_path = content_type_from_path 71 self.content_type = content_type
72
73 -class HttpCgiError:
74 - def __init__(self, *args):
75 self.args = args
76
77 -class HttpMethodError(HttpCgiError):
78 pass
79
80 -def getkwargs(httpreq,environment):
81 if environment['REQUEST_METHOD'].lower() == 'post': 82 environment['REQUEST_METHOD'] = 'GET' 83 kwargs = getkwargs(httpreq, environment) 84 environment['REQUEST_METHOD'] = 'POST' 85 else: 86 kwargs = {} 87 fields = cgi.FieldStorage(fp=httpreq.rfile,environ=environment) 88 for x in fields.keys(): 89 if fields[x].filename is None: 90 kwargs[x] = fields.getvalue(x) 91 else: 92 kwargs[x] = fields[x] 93 return kwargs
94
95 -def webmethodwrite(httpreq, res, returntype, headers=(), options={}):
96 """ |headers| can be one of the following: 97 - A dictionary 98 - A tuple/list of tuple/list of two elements 99 - A tuple/list of a string per entry 100 - A mixin of the previous two 101 """ 102 wfile = httpreq.wfile 103 wfile.write("Content-Type: " + returntype + "\r\n") 104 env,_headers = getthreaddata() # getrequest() 105 # print env 106 try: 107 res.read 108 isfile = True 109 except AttributeError,e: 110 isfile = False 111 res = str(res) 112 113 try: 114 if isfile: 115 raise KeyError("Refuse to compress a direct file") 116 for enc in env['HTTP_ACCEPT_ENCODING'].split(","): 117 enc = enc.strip() 118 if not enc.endswith("gzip"): 119 continue 120 string = StringIO() 121 gzfile = gzip.GzipFile(filename=None, mode="wb", fileobj = string) 122 gzfile.write(res) 123 gzfile.flush() 124 gzfile.close() 125 res = string.getvalue() 126 wfile.write("Content-Encoding: %s\r\n"%enc) 127 break 128 wfile.write("Content-Length: %d\r\n"%len(res)) 129 except (ValueError, KeyError, TypeError): 130 pass 131 try: 132 items = headers.items() 133 except AttributeError: 134 items = headers 135 _headers.extend(items) 136 _headers.append(("Connection","close")) 137 for item in _headers: 138 try: 139 name,value = item 140 wfile.write(name) 141 wfile.write(": ") 142 wfile.write(str(value)) 143 except ValueError: 144 wfile.write(item) 145 wfile.write("\r\n") 146 wfile.write("\r\n") 147 if isfile: 148 shutil.copyfileobj(res, wfile) 149 try: 150 res.close() 151 except Exception, e: 152 warn.warn("Error closing webmethod response: ", e) 153 else: 154 wfile.write(res) 155 wfile.flush()
156
157 -def webmethod(httpreq, environment, method, returntype="text/plain"):
158 kwargs = getkwargs(httpreq, environment) 159 res = str(method(**kwargs)) 160 webmethodwrite(httpreq, res, returntype)
161 162 import Cookie, urllib
163 -def getcookiespyroauth(authcookiename,environment):
164 try: 165 c = environment['HTTP_COOKIE'] 166 cookies = Cookie.SimpleCookie() 167 cookies.load(c) 168 values = urllib.unquote(cookies[authcookiename].value) 169 values = values.split(',') 170 x = [ urllib.unquote(cookies[v].value) for v in values ] 171 return x 172 except KeyError: 173 return None
174
175 -def webspyro(spyroserver, httpreq, environment, returntype="text/plain", authcookiename='SPyRO_AuthMethod'):
176 try: 177 path = environment['PATH_INFO'].lstrip("/") 178 if not path: raise KeyError 179 except KeyError: 180 path = 'index' 181 parts = [ environment['SCRIPT_NAME'].split('/')[-1] ] 182 parts.extend( path.split("/") ) 183 objname = ".".join(parts[:-1]) 184 attrname = parts[-1] 185 kwargs = getkwargs(httpreq, environment) 186 auth = getcookiespyroauth(authcookiename,environment) 187 # print (objname, attrname, (), kwargs, auth) 188 res = spyroserver.handle_request(objname, attrname, (), kwargs, auth, reqtype='CALL') 189 if res['errcode'] != 0: 190 raise HttpMethodError(res) 191 webmethodwrite(httpreq, res['retvalue'], returntype)
192 193
194 -def httpcall(realhandler,returntype='text/plain'):
195 """ Creates a lexical closure to execute a function with 196 query_string and post requests as function arguments 197 |realhandler| The handler of the call 198 |returntype| The return type of the function to be placed as 199 Content-Type header 200 201 Note: If httpcall is used as decorator the declared function 202 will be replaced, use regcall of http object as decorator. 203 204 """ 205 def directcall(httpreq, environment): 206 webmethod(httpreq, environment, realhandler, returntype)
207 return directcall 208
209 -def httpcallspyro(spyroserver, returntype='text/plain', authcookiename='SPyRO_AuthMethod'):
210 """ Creates a lexical closure to execute a function with 211 query_string and post requests as function arguments 212 |spyroserver| The SPyRO server to the call 213 214 If the proper authorization policies aren't disabled (policy 'can_follow_objname'): 215 /SPyRO/Chart/Bar/Draw 216 /SPyRO -> Registered URL base to spyroserver 217 /Chart -> Object 218 /Bar -> A property of /Chart 219 /Draw -> A method of /Bar 220 221 |returntype| The return type of the function to be placed as 222 Content-Type header 223 224 Note: If httpcall is used as decorator the declared function 225 will be replaced, use regcall of http object as decorator. 226 227 """ 228 def directcall(httpreq, environment): 229 webspyro(spyroserver, httpreq, environment, returntype, authcookiename)
230 return directcall 231
232 -class HTTPWriteWrapper:
233 - def __init__(self, http):
234 self.http = http 235 self.wfile = http.wfile 236 self.response = None 237 self.closed = False
238
239 - def change(self):
240 if self.closed: return 241 self.http.wfile = self.wfile 242 self.write = self.wfile.write 243 self.flush = self.wfile.flush 244 self.close = self.wfile.close 245 self.closed = True 246 if not self.response.startswith("HTTP/"): 247 self.http.send_response(200,"CGI output follows") 248 self.wfile.write(self.response)
249
250 - def write(self, data):
251 if self.response is None: 252 self.response = data 253 else: 254 self.response = self.response + data 255 if len(self.response) >= 5: 256 self.change() 257 else: 258 if self.response in ("H","HT","HTTP"): 259 return 260 else: 261 self.change()
262
263 - def flush(self):
264 self.change()
265
266 - def close(self):
267 self.change()
268
269 - def __del__(self):
270 self.change()
271
272 -class HTTPRequestHandler(CGIHTTPRequestHandler):
273 - def translate_path(self, path, root=None):
274 """ 275 Translate a /-separated PATH to the local filename syntax. 276 277 Components that mean special things to the local file system 278 (e.g. drive or directory names) are ignored. 279 (XXX They should probably be diagnosed.) 280 281 """ 282 # abandon query parameters 283 # path = urlparse.urlparse(path)[2] 284 # path = posixpath.normpath(urllib.unquote(path)) 285 words = path.split('?')[0].split('/') 286 words = filter(None, words) 287 final = [] 288 for word in words: 289 drive, word = os.path.splitdrive(word) 290 head, word = os.path.split(word) 291 if word == os.curdir: continue 292 if word == os.pardir: 293 try: 294 del final[-1] 295 except IndexError: 296 pass 297 final.append(word) 298 sep = os.sep 299 return self.virtual_host.document_root + sep + sep.join(final)
300
301 - def parse_request(self):
302 res = CGIHTTPRequestHandler.parse_request(self) 303 parsed = urlparse.urlparse(self.path) 304 self.path = urllib.unquote(posixpath.normpath(parsed[2])) 305 if parsed[2][-1] == '/': 306 if parsed[2] != '/': 307 self.path = self.path + "/" 308 if parsed[-2] != '': 309 self.path = "%s?%s"%(self.path, urllib.unquote(parsed[-2])) 310 self.virtual_host = self.server.get_virtual_host(self.headers.get('Host')) 311 self.cgi_directories = self.virtual_host.cgi_directories 312 if self.virtual_host.rewrite_function: 313 self.virtual_host.rewrite_function(self) 314 return res
315
316 - def setup(self):
317 self.connection = self.request 318 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) 319 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
320
321 - def handle(self):
322 CGIHTTPRequestHandler.handle(self)
323 # self.request.close() 324
325 - def is_cgi(self):
326 """ Checks if the URI corresponds to a CGI or a Python Handler """ 327 cgi_handlers = self.virtual_host.cgi_handlers 328 path = self.path.split('?',1)[0] 329 # The order is not directly predectible 330 handler = None 331 keys = cgi_handlers.keys() 332 keys.sort() 333 334 for x in keys: 335 i = len(x) 336 prefix = path[:i] 337 # if prefix == x and (not prefix or path[i] == '/'): 338 # warn.debug( "i: %s, key: %s, path: %s, prefix: %s"%(i, x, path, prefix) ) 339 if prefix == x and (len(path) == i or path[i] == '/'): 340 self.cgi_info = path[:i], re.sub(r"^/+","",self.path[i:]), cgi_handlers[x] 341 return True 342 return CGIHTTPRequestHandler.is_cgi(self)
343
344 - def check_script_sanity(self, scriptname, scriptfile):
345 """ Returns True if running the script is OK, False otherwise """ 346 if not os.path.exists(scriptfile): 347 self.send_error(404, "No such CGI script (%r)" % scriptname) 348 return False 349 if not os.path.isfile(scriptfile): 350 self.send_error(403, "CGI script is not a plain file (%r)" % 351 scriptname) 352 return False 353 ispy = self.is_python(scriptname) 354 if not ispy: 355 if not (self.have_fork or self.have_popen2 or self.have_popen3): 356 self.send_error(403, "CGI script is not a Python script (%r)" % 357 scriptname) 358 return False 359 if not self.is_executable(scriptfile): 360 self.send_error(403, "CGI script is not executable (%r)" % 361 scriptname) 362 return False 363 return True
364
365 - def address_string(self):
366 return self.client_address[0]
367
368 - def get_environ(self):
369 """Execute a CGI script.""" 370 if len(self.cgi_info) == 3: 371 dir, rest, handler = self.cgi_info 372 else: 373 dir, rest = self.cgi_info 374 handler = None 375 i = rest.rfind('?') 376 # warn.debug("REST:",rest, ', PATH: ', self.path) 377 if i >= 0: 378 rest, query = rest[:i], rest[i+1:] 379 else: 380 query = '' 381 # warn.debug("REST2:",rest, ", QUERY:",query) 382 self.query = query 383 i = rest.find('/') 384 if i >= 0: 385 script, rest = rest[:i], rest[i:] 386 else: 387 script, rest = rest, '' 388 # warn.debug("SCRIPT:",script, ", REST:",rest) 389 self.script = script 390 self.scriptname = scriptname = dir + '/' + script 391 self.scriptfile = scriptfile = self.translate_path(scriptname) 392 # warn.debug("script:", script, ", scriptname:" + scriptname, ', scriptfile:' + scriptfile) 393 394 if handler is None: # CGI 395 if not self.check_script_sanity(scriptname, scriptfile): 396 raise HttpCgiError("Unable to run %s => %s as CGI"%(scriptname, scriptfile)) 397 # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html 398 # XXX Much of the following could be prepared ahead of time! 399 env = {} 400 for k,v in self.headers.items(): 401 env["HTTP_%s"%(k.replace("-","_").upper())] = v 402 length = self.headers.getheader('content-length') 403 if length: 404 env['CONTENT_LENGTH'] = length 405 self.length = length 406 if query: 407 env['QUERY_STRING'] = query 408 env['REQUEST_METHOD'] = self.command 409 # useful for spyro and other simple handlers 410 # if self.simple_environ: return env 411 env['SERVER_SOFTWARE'] = self.version_string() 412 env['SERVER_NAME'] = self.request.getsockname()[0] #self.server.server_name 413 env['GATEWAY_INTERFACE'] = 'CGI/1.1' 414 env['SERVER_PROTOCOL'] = self.protocol_version 415 env['SERVER_PORT'] = str(self.server.server_address[1]) 416 uqrest = urllib.unquote(rest) 417 env['PATH_INFO'] = uqrest 418 # env['PATH_TRANSLATED'] = 'No-Available' # self.translate_path(uqrest) 419 env['SCRIPT_NAME'] = scriptname 420 #host = self.address_string() 421 #if host != self.client_address[0]: 422 env['REMOTE_HOST'] = env['REMOTE_ADDR'] = self.client_address[0] 423 authorization = self.headers.getheader("authorization") 424 if authorization: 425 authorization = authorization.split() 426 if len(authorization) == 2: 427 import base64, binascii 428 env['AUTH_TYPE'] = authorization[0] 429 if authorization[0].lower() == "basic": 430 try: 431 authorization = base64.decodestring(authorization[1]) 432 except binascii.Error: 433 pass 434 else: 435 authorization = authorization.split(':') 436 if len(authorization) == 2: 437 env['REMOTE_USER'] = authorization[0] 438 # XXX REMOTE_IDENT 439 if self.headers.typeheader is None: 440 env['CONTENT_TYPE'] = self.headers.type 441 else: 442 env['CONTENT_TYPE'] = self.headers.typeheader 443 accept = [] 444 for line in self.headers.getallmatchingheaders('accept'): 445 if line[:1] in "\t\n\r ": 446 accept.append(line.strip()) 447 else: 448 accept = accept + line[7:].split(',') 449 env['HTTP_ACCEPT'] = ','.join(accept) 450 co = filter(None, self.headers.getheaders('cookie')) 451 if co: 452 env['HTTP_COOKIE'] = ', '.join(co) 453 # XXX Other HTTP_* headers 454 # Since we're setting the env in the parent, provide empty 455 # values to override previously set values 456 for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', 457 'HTTP_USER_AGENT', 'HTTP_COOKIE'): 458 env.setdefault(k, "") 459 return env
460
461 - def run_cgi(self):
462 """Execute a CGI script.""" 463 self.scriptname = self.scriptfile = self.query = self.length = None 464 env = self.get_environ() 465 query = self.query 466 scriptname = self.scriptname 467 scriptfile = self.scriptfile 468 length = self.length 469 decoded_query = query.replace('+', ' ') 470 self.wfile = HTTPWriteWrapper(self) 471 _setrequest(env) 472 if len(self.cgi_info) == 3: 473 try: 474 handler = self.cgi_info[2] 475 handler(self, env) 476 except CustomResponse, resp: 477 self.send_response(resp.status, resp.reason) 478 if resp.content_type_from_path: 479 resp.content_type = self.guess_type(resp.content_type_from_path) 480 webmethodwrite(self, resp.data, resp.content_type, resp.headers, options=resp.options) 481 except: 482 type, value, traceback = sys.exc_info() 483 if isinstance(value, HttpMethodError): 484 error = repr(value.args) 485 elif isinstance(value, Exception): 486 try: 487 error = repr(value.message) 488 except AttributeError: 489 error = repr(value) 490 else: 491 error = repr(value) 492 if self.virtual_host.show_errors: 493 weberror = error 494 else: 495 weberror = "Private error, please contact with your system administrator" 496 self.send_response(500, "Internal Server Error: %s"%error) 497 warn.warn("Internal Error", self.cgi_info, ". Exception: ", error) 498 webmethodwrite(self, 'Internal Server Error: %s'%error, 'text/plain') 499 _delrequest() 500 return 501 if self.have_fork and not self.server.usingssl: 502 # Unix -- fork as we should 503 args = [self.script] 504 if '=' not in decoded_query: 505 args.append(decoded_query) 506 nobody = nobody_uid() 507 self.wfile.flush() # Always flush before forking 508 pid = os.fork() 509 if pid != 0: 510 # Parent 511 pid, sts = os.waitpid(pid, 0) 512 # throw away additional data [see bug #427345] 513 while select.select([self.rfile], [], [], 0)[0]: 514 if not self.rfile.read(1): 515 break 516 if sts: 517 self.log_error("CGI script exit status %#x", sts) 518 _delrequest() 519 return 520 # Child 521 try: 522 try: 523 os.setuid(nobody) 524 except os.error: 525 pass 526 os.dup2(self.rfile.fileno(), 0) 527 os.dup2(self.wfile.fileno(), 1) 528 os.execve(scriptfile, args, env) 529 except: 530 self.server.handle_error(self.request, self.client_address) 531 os._exit(127) 532 533 elif self.have_popen2 or self.have_popen3: 534 # Windows -- use popen2 or popen3 to create a subprocess 535 if self.have_popen3: 536 popenx = os.popen3 537 else: 538 popenx = os.popen2 539 cmdline = scriptfile 540 if self.is_python(scriptfile): 541 interp = sys.executable 542 if interp.lower().endswith("w.exe"): 543 # On Windows, use python.exe, not pythonw.exe 544 interp = interp[:-5] + interp[-4:] 545 cmdline = "%s -u %s" % (interp, cmdline) 546 if '=' not in query and '"' not in query: 547 cmdline = '%s "%s"' % (cmdline, query) 548 self.log_message("command: %s", cmdline) 549 try: 550 nbytes = int(length) 551 except (TypeError, ValueError): 552 nbytes = 0 553 files = popenx(cmdline, 'b') 554 fi = files[0] 555 fo = files[1] 556 if self.have_popen3: 557 fe = files[2] 558 if self.command.lower() == "post" and nbytes > 0: 559 data = self.rfile.read(nbytes) 560 fi.write(data) 561 # throw away additional data [see bug #427345] 562 while select.select([self.rfile._sock], [], [], 0)[0]: 563 if not self.rfile._sock.recv(1): 564 break 565 fi.close() 566 shutil.copyfileobj(fo, self.wfile) 567 if self.have_popen3: 568 errors = fe.read() 569 fe.close() 570 if errors: 571 self.log_error('%s', errors) 572 sts = fo.close() 573 if sts: 574 self.log_error("CGI script exit status %#x", sts) 575 else: 576 self.log_message("CGI script exited OK") 577 578 else: 579 # Other O.S. -- execute script in this process 580 save_argv = sys.argv 581 save_stdin = sys.stdin 582 save_stdout = sys.stdout 583 save_stderr = sys.stderr 584 try: 585 save_cwd = os.getcwd() 586 try: 587 sys.argv = [scriptfile] 588 if '=' not in decoded_query: 589 sys.argv.append(decoded_query) 590 sys.stdout = self.wfile 591 sys.stdin = self.rfile 592 execfile(scriptfile, {"__name__": "__main__"}) 593 finally: 594 sys.argv = save_argv 595 sys.stdin = save_stdin 596 sys.stdout = save_stdout 597 sys.stderr = save_stderr 598 os.chdir(save_cwd) 599 except SystemExit, sts: 600 self.log_error("CGI script exit status %s", str(sts)) 601 else: 602 self.log_message("CGI script exited OK") 603 _delrequest()
604
605 - def log_message(self, format, *args):
606 warn._write("%s - - [%s] %s\n" % (self.address_string(), self.log_date_time_string(), format%args))
607
608 -class VirtualHost:
609 - def __init__(self, name, document_root, cgi_handlers, cgi_directories, show_errors, rewrite_function=None):
610 self.name = name 611 self.document_root = document_root 612 self.cgi_handlers = cgi_handlers 613 self.cgi_directories = cgi_directories 614 self.show_errors = show_errors 615 self.rewrite_function = rewrite_function
616
617 -class HTTPServer(ThreadingTCPServer,httpbase):
618 - def __init__(self, 619 server_address, # A tuple with the server address 620 HandlerClass = HTTPRequestHandler, # The handler class of the request 621 ssl_privatekey_file=None, # You must set this argument if you need HTTPS 622 ssl_certificate_file=None,# You must set this argument if you need HTTPS 623 ssl_method=None, # You must set this argument if you need HTTPS (version) 624 cgi_handlers=None, # CGI handlers. A dict of handlers (url => handler function) 625 cgi_directories=None, # Directories that must be handled as cgi directories 626 document_root=".", # The document root 627 request_queue_size=1024, # The queue size 628 show_errors=True, # if true the errors will be shown in the http response, if false only in the logs 629 virtual_hosts=None # A dictionary of VirtualHost objects 630 ):
631 # ThreadingTCPServer.__init__(self, server_address, HandlerClass) 632 ThreadingTCPServer.request_queue_size = request_queue_size 633 try: 634 warn.debug("reading /etc/mime.types...") 635 f = file("/etc/mime.types") 636 for l in f.readlines(): 637 if l.startswith("#"): continue 638 mimes = l.rstrip().split() 639 for ext in mimes[1:]: 640 HandlerClass.extensions_map[ext] = mimes[0] 641 except Exception,e: 642 warn.warn(e) 643 ThreadingTCPServer.__init__(self, server_address, HandlerClass) 644 if cgi_handlers is None: 645 cgi_handlers = {} 646 self.cgi_handlers = cgi_handlers 647 self.show_errors = show_errors 648 self.document_root = document_root 649 # self.cgi_handlers['/hello'] = self.helloworld 650 # self.cgi_handlers['/spyro'] = self.spyro 651 if cgi_directories is None: cgi_directories = [] 652 self.cgi_directories = cgi_directories 653 self.usingssl = False 654 self.process_next_request = True 655 if virtual_hosts is None: 656 virtual_hosts = { } 657 self.virtual_hosts = virtual_hosts 658 try: 659 virtual_hosts[''] 660 except KeyError: 661 virtual_hosts[''] = VirtualHost(server_address[0],document_root,cgi_handlers,cgi_directories,show_errors) 662 663 if ssl_privatekey_file: 664 if ssl_method is None: ssl_method = SSL.SSLv23_METHOD 665 self.usingssl = True 666 context = SSL.Context(ssl_method) 667 # server.pem's location (containing the server private key and 668 # the server certificate). 669 context.use_privatekey_file(ssl_privatekey_file) 670 context.use_certificate_file(ssl_certificate_file) 671 self.socket = SSL.Connection(context, socket.socket(self.address_family, 672 self.socket_type)) 673 self.reuse_address() 674 self.server_bind() 675 httpbase.server_activate(self)
676 allow_reuse_address = True 677
678 - def get_virtual_host(self, virtual_host=''):
679 try: 680 return self.virtual_hosts[virtual_host] 681 except KeyError: 682 return self.virtual_hosts['']
683
684 - def reuse_address(self):
685 if not self.allow_reuse_address: 686 return 687 try: 688 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 689 except socket.error, err: 690 warn.debug("SO_REUSEADDR is not supported: ",err)
691
692 - def server_bind(self):
693 """Called by constructor to bind the socket. 694 695 May be overridden. 696 697 """ 698 self.reuse_address() 699 SocketServer.TCPServer.server_bind(self) 700 host, port = self.socket.getsockname()[:2] 701 self.server_name = socket.getfqdn(host) 702 self.server_port = port 703 #self.socket.bind(self.server_address) 704 self.server_address = self.socket.getsockname()
705
706 - def register_urihandler(self, uri, handler, virtual_host=''):
707 """ Set an urihandler 708 |uri| The URI to be handled 709 |handler| a function that handles the event 710 |virtual_host| The name of the virtual host, default to '' (default virtual host) 711 Prototype: 712 function(httpreq, environment) 713 httpreq is an HTTPRequestHandler Object 714 """ 715 self.virtual_hosts[virtual_host].cgi_handlers[uri] = handler
716
717 - def unregister_urihandler(self, uri, virtual_host=''):
718 """Deletes the uri-handler associated to |uri| 719 |virtual_host| The name of the virtual host, default to '' (default virtual host) 720 """ 721 del self.virtual_hosts[virtual_host].cgi_handlers[uri]
722
723 - def helloworld(self, httpreq, environment):
724 print environment 725 print httpreq.cgi_info 726 print httpreq.path 727 print "*" * 30 728 wfile = httpreq.wfile 729 wfile.write("""Content-Type: text/plain 730 731 Hola mundo 732 733 Primer programa con script handlers 734 """)
735
736 - def regobj(self, uri, object, returntype="text/plain", authority=None):
737 def handler(httpreq, environment): 738 res = httpreq.cgi_info[1] 739 method = object 740 for x in res.split('?')[0].split('/'): 741 if x == '': continue 742 method = getattr(method,x) 743 webmethod(httpreq, environment, method, returntype)
744 self.register_urihandler(uri, handler) 745 return object
746
747 - def regcall(self, uri, returntype='text/plain'):
748 """ Register uri |uri| to be handled by a function 749 This method can be used safelly as decorator 750 751 Example 752 @httpobj.regcall('/selected-uri','text/html') 753 def square(x): 754 int(x) 755 return x*x 756 """ 757 def decorator(function): 758 self.register_urihandler(uri, httpcall(function, returntype)) 759 return function
760 return decorator 761
762 - def serve_forever(self):
763 """ Handles requestgs while self.process_next_request is True """ 764 while self.process_next_request: 765 self.handle_request()
766 767
768 - def process_request(self, request, client_address):
769 """ Process one request, overloaded to support implement trusted 770 SSL under heavy load """ 771 if self.usingssl: 772 TCPServer.process_request(self, request, client_address) 773 else: 774 ThreadingTCPServer.process_request(self, request, client_address)
775
776 - def close(self):
777 self.process_next_request = False 778 self.socket.settimeout(0) 779 self.socket.shutdown(socket.SHUT_RDWR)
780