httpAPI.py :  » Network » Grail-Internet-Browser » grail-0.6 » protocols » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Grail Internet Browser 
Grail Internet Browser » grail 0.6 » protocols » httpAPI.py
"""Provisional HTTP interface using the new protocol API.

XXX This was hacked together in an hour si I would have something to
test ProtocolAPI.py.  Especially the way it uses knowledge about the
internals of httplib.HTTP is disgusting (but then, so would editing
the source of httplib.py be :-).

XXX Main deficiencies:

- poll*() always returns ready
- should read the headers more carefully (no blocking)
- (could even *write* the headers more carefully)
- should poll the connection making part too

"""


import string
import httplib
from urllib import splithost
import mimetools
from Assert import Assert
import grailutil
import select
import Reader
import regex
import StringIO
import socket
import sys
from __main__ import GRAILVERSION


httplib.HTTP_VERSIONS_ACCEPTED = 'HTTP/1\.[0-9.]+'
replypat = httplib.HTTP_VERSIONS_ACCEPTED + '[ \t]+\([0-9][0-9][0-9]\)\(.*\)'
replyprog = regex.compile(replypat)

httplib.replypat = replypat
httplib.replyprog = replyprog


# Search for blank line following HTTP headers
endofheaders = regex.compile("\n[ \t]*\r?\n")


# Stages
# there are now five stages
WAIT = 'wait'  # waiting for a socket
META = 'meta'
DATA = 'data'
DONE = 'done'
CLOS = 'closed'

class MyHTTP(httplib.HTTP):

    def putrequest(self, request, selector):
        self.selector = selector
        httplib.HTTP.putrequest(self, request, selector)

    def getreply(self, file):
        self.file = file
        line = self.file.readline()
        if self.debuglevel > 0: print 'reply:', `line`
        if replyprog.match(line) < 0:
            # Not an HTTP/1.0 response.  Fall back to HTTP/0.9.
            # Push the data back into the file.
            self.file.seek(-len(line), 1)
            self.headers = {}
            app = grailutil.get_grailapp()
            c_type, c_encoding = app.guess_type(self.selector)
            if c_encoding:
                self.headers['content-encoding'] = c_encoding
            # HTTP/0.9 sends HTML by default
            self.headers['content-type'] = c_type or "text/html"
            return 200, "OK", self.headers
        errcode, errmsg = replyprog.group(1, 2)
        errcode = string.atoi(errcode)
        errmsg = string.strip(errmsg)
        self.headers = mimetools.Message(self.file, 0)
        return errcode, errmsg, self.headers

    def close(self):
        if self.file:
            self.file.close()
        if self.sock:
            try:
                self.sock.close()
            except socket.error:
                # What can you do? :-)
                pass
        self.file = None
        self.sock = None


class http_access:

    def __init__(self, resturl, method, params, data=None):
        self.app = grailutil.get_grailapp()
        self.args = (resturl, method, params, data)
        self.state = WAIT
        self.h = None
        self.reader_callback = None
        self.app.sq.request_socket(self, self.open)

    def register_reader(self, reader_callback, ignore):
        if self.state == WAIT:
            self.reader_callback = reader_callback
        else:
            # we've been waitin' fer ya
            reader_callback()

    def open(self):
        Assert(self.state == WAIT)
        resturl, method, params, data = self.args
        if data:
            Assert(method=="POST")
        else:
            Assert(method in ("GET", "POST"))
        if type(resturl) == type(()):
            host, selector = resturl    # For proxy interface
        else:
            host, selector = splithost(resturl)
        if not host:
            raise IOError, "no host specified in URL"
        i = string.find(host, '@')
        if i >= 0:
            user_passwd, host = host[:i], host[i+1:]
        else:
            user_passwd = None
        if user_passwd:
            import base64
            auth = string.strip(base64.encodestring(user_passwd))
        else:
            auth = None
        self.h = MyHTTP(host)
        self.h.putrequest(method, selector)
        self.h.putheader('User-agent', GRAILVERSION)
        if auth:
            self.h.putheader('Authorization', 'Basic %s' % auth)
        if not params.has_key('host'):
            self.h.putheader('Host', host)
        if not params.has_key('accept-encoding'):
            encodings = Reader.get_content_encodings()
            if encodings:
                encodings.sort()
                self.h.putheader(
                    'Accept-Encoding', string.join(encodings, ", "))
        for key, value in params.items():
            if key[:1] != '.':
                self.h.putheader(key, value)
        self.h.putheader('Accept', '*/*')
        self.h.endheaders()
        if data:
            self.h.send(data)
        self.readahead = ""
        self.state = META
        self.line1seen = 0
        if self.reader_callback:
            self.reader_callback()

    def close(self):
        if self.h:
            self.h.close()
        if self.state != CLOS:
            self.app.sq.return_socket(self)
            self.state = CLOS
        self.h = None

    def pollmeta(self, timeout=0):
        Assert(self.state == META)

        sock = self.h.sock
        try:
            if not select.select([sock], [], [], timeout)[0]:
                return "waiting for server response", 0
        except select.error, msg:
            raise IOError, msg, sys.exc_traceback
        try:
            new = sock.recv(1024)
        except socket.error, msg:
            raise IOError, msg, sys.exc_traceback
        if not new:
            return "EOF in server response", 1
        self.readahead = self.readahead + new
        if '\n' not in new:
            return "receiving server response", 0
        if not self.line1seen:
            i = string.find(self.readahead, '\n')
            if i < 0:
                return "receiving server response", 0
            self.line1seen = 1
            line = self.readahead[:i+1]
            if replyprog.match(line) < 0:
                return "received non-HTTP/1.0 server response", 1
        i = endofheaders.search(self.readahead)
        if i >= 0:
            return "received server response", 1
        return "receiving server response", 0

    def getmeta(self):
        Assert(self.state == META)
        if not self.readahead:
            x, y = self.pollmeta(None)
            while not y:
                x, y = self.pollmeta(None)
        file = StringIO.StringIO(self.readahead)
        errcode, errmsg, headers = self.h.getreply(file)
        self.state = DATA
        self.readahead = file.read()
        return errcode, errmsg, headers

    def polldata(self):
        Assert(self.state == DATA)
        if self.readahead:
            return "processing readahead data", 1
        return ("waiting for data",
                len(select.select([self], [], [], 0)[0]))

    def getdata(self, maxbytes):
        Assert(self.state == DATA)
        if self.readahead:
            data = self.readahead[:maxbytes]
            self.readahead = self.readahead[maxbytes:]
            return data
        try:
            data = self.h.sock.recv(maxbytes)
        except socket.error, msg:
            raise IOError, msg, sys.exc_traceback
        if not data:
            self.state = DONE
            # self.close()
        return data

    def fileno(self):
        return self.h.sock.fileno()


# To test this, use ProtocolAPI.test()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.