We can get connection from FS now
[ipypbx] / src / ipypbx / http.py
1 # Copyright (c) Stas Shtin, 2010
2
3 # This file is part of IPyPBX.
4
5 # IPyPBX is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9
10 # IPyPBX is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with IPyPBX.  If not, see <http://www.gnu.org/licenses/>.
17
18 from PyQt4 import QtCore, QtNetwork
19
20
21 class FreeswitchConfigServer(QtNetwork.QTcpServer):
22     """
23     TCP server that receives config requests from freeswitch.
24     """
25     def __init__(self, parent=None):
26         super(FreeswitchConfigServer, self).__init__(parent)
27
28         self.host = None
29         self.port = None
30         self.is_running = False
31         
32         self.httpRequestParser = HttpRequestParser()
33         
34     def setSocketData(self, host, port):
35         """
36         Set host and port for socket to listen on.
37         """
38         self.host = host
39         self.port = port
40
41     def startServer(self):
42         """
43         Start listening on our socket.
44         """
45         if not self.is_running:
46             if self.host and self.port:
47                 self.newConnection.connect(self.clientConnecting)
48                 self.listen(QtNetwork.QHostAddress(self.host), self.port)
49                 self.is_running = True
50
51     def stopServer(self):
52         """
53         Stop listening on our socket.
54         """
55         if self.is_running:
56             self.close()
57             self.is_running = False
58
59     def restartServer(self):
60         """
61         Restart server.
62         """
63         self.stopServer()
64         self.startServer()
65
66     def clientConnecting(self):
67         """
68         Handle client connection.
69         """
70         if self.hasPendingConnections():
71             self.socket = self.nextPendingConnection()
72             self.socket.readyRead.connect(self.receiveData)
73
74     def receiveData(self):
75         while self.socket.canReadLine():
76             line = str(self.socket.readLine()).strip()
77             print '<', line
78             self.httpRequestParser.handle(line)
79             
80
81 class HttpParseError(Exception):
82     """
83     Error parsing HTTP request.
84     """
85
86
87 class HttpRequestParser(object):
88     """
89     A simple state machine for parsing HTTP requests.
90     """
91     HTTP_NONE, HTTP_REQUEST, HTTP_HEADERS, HTTP_EMPTY, HTTP_MESSAGE = range(5)
92     HTTP_STATES = ['NONE', 'REQUEST', 'HEADERS', 'EMPTY', 'MESSAGE']
93     
94     def __init__(self):
95         super(HttpRequestParser, self).__init__()
96         self.reset()
97
98     def reset(self):
99         """
100         Reset parser to initial state.
101         """
102         # Initial values for request data.
103         self.method = None
104         self.request_path = None
105         self.http_version = None
106         self.message = ''
107         
108         # Set initial state.
109         self.state = self.HTTP_NONE        
110
111     def handle(self, line):
112         """
113         Dispatch line to current state handler.
114         """
115         for state in self.HTTP_STATES:
116             if getattr(self, 'HTTP_%s' % state) == self.state:
117                 getattr(self, 'handle%s' % state.title())(line)
118                 break
119         else:
120             raise HttpParseError('Unknown HTTP state')
121                 
122     def handleNone(self, line):
123         """
124         Pass line to next state.
125         """
126         self.state += 1
127         self.handle(line)
128
129     def handleRequest(self, line):
130         """
131         Retrieve HTTP method, request path and HTTP version from request.
132         """
133         self.method, self.request_path, self.http_version = line.split(' ')
134         self.state += 1
135
136     def handleHeaders(self, line):
137         """
138         Parse headers while not found an empty line.
139         """
140         if line:
141             key, value = line.split(': ')
142             self.headers[key] = value
143         else:
144             self.state += 1
145
146     def handleEmpty(self, line):
147         """
148         Empty line separator is found - proceed to next state.
149         """
150         self.state += 1
151
152     def handleMessage(self, line):
153         """
154         Append to message body.
155         """
156         self.message += line