Palm Server: Fix POST data support
[MonkeyD.git] / palm / lib / child.py
blob1299c111f196e62c3d12912505d66c02ccea564f
1 # Copyright (C) 2008-2009, Eduardo Silva <edsiper@gmail.com>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 import os
18 import sys
19 import time
20 import signal
21 import fcntl
22 from debug import *
24 class Child:
25 def __init__(self, name, socket, parent):
26 # Listener socket
27 self.name = name
28 self._s = socket
30 # Parent Object
31 self.parent = parent
32 self.split_conf()
34 # On child end, re-create it
35 signal.signal(signal.SIGCHLD, self._child_exit)
37 # Start our child
38 self._create()
40 def split_conf(self):
41 try:
42 opts = self.parent.opts.split()
43 except:
44 opts = []
46 self.c = {'bin': self.parent.bin, 'opts': opts}
48 def _create(self):
49 # Fork process
50 pid = os.fork()
51 if pid:
52 self._pid = pid
53 msg = " Creating '%s' child PID %i" % (self.name, pid)
54 debug(msg)
55 else:
56 # Start child loop
57 self.start_loop()
59 def _child_exit(self,a, b):
60 os.wait()
61 debug("[-] Exit child '%s'" % self.name)
62 self._create()
64 def read(self, fd):
65 buf = ""
66 while 1:
67 data = fd.recv(4096)
68 if len(data) == 0:
69 break
70 else:
71 buf += data
72 if buf[-4:] == '\r\n\r\n':
73 break;
75 return buf
77 def parse_request(self, data):
78 arr = data.split('\r\n')
79 request = None
81 for line in arr[:-2]:
82 # print line
83 if line == arr[0]:
84 request = Request(line)
85 continue
87 sep = line.find('=')
88 if sep < 0:
89 continue
91 key = line[:sep]
92 val = line[sep+1:]
94 if key == 'POST_VARS' and len(val) > 0:
95 val = '*'
97 # Register key value
98 request.add_header(key, val)
101 # Post-parse POST data
102 if request.get('POST_VARS') == '*':
103 init_key = '\r\nPOST_VARS='
104 len_key = len(init_key)
106 post_len = int(request.get('CONTENT_LENGTH'))
107 post_data = data.find(init_key)
109 # Set string offsets
110 offset_init = post_data + len_key
111 offset_end = post_data + len_key + post_len
113 # Override POST_VARS
114 request.add_header('POST_VARS', data[offset_init:offset_end])
116 if request is None:
117 debug("[+] Invalid Exit")
118 exit(1)
120 # Debug message
121 msg = "[+] Request Headers\n"
122 for h in request.headers:
123 msg += ' ' + h + ' = \'' + request.headers[h] + '\'\n'
124 msg += "[-] Request End"
125 debug(msg)
127 return request
129 def start_loop(self):
130 # Creating epoll for read pipe side
131 while 1:
132 remote, info = self._s.accept()
133 remote_fd = remote.fileno()
135 # Close on exec
136 flags = fcntl.fcntl(remote_fd, fcntl.F_GETFD)
137 try:
138 flags |= fcntl.FD_CLOEXEC
139 except AttributeError, e:
140 flags |= 1
142 fcntl.fcntl(remote_fd, fcntl.F_SETFD, flags)
144 debug("[+] |%s| Request arrived [PID=%i]" % (self.name, os.getpid()))
146 buf = self.read(remote)
147 print buf
148 request = self.parse_request(buf)
150 if self.c['bin'] is None:
151 bin = request.resource
152 else:
153 bin = self.c['bin']
155 if self.c['opts'] is None and bin != request.resource:
156 opts = [request.resource]
157 else:
158 opts = self.c['opts']
159 opts.append(request.resource)
161 print "***"
162 print request.headers['POST_VARS']
163 print "***"
164 try:
165 os.dup2(remote.fileno(), sys.stdout.fileno())
167 # Write Post data to STDIN (Pipe)
168 if request.headers['REQUEST_METHOD'] == 'POST':
169 # Temporal Pipe > STDIN
170 pipe_r, pipe_w = os.pipe()
171 os.dup2(pipe_r, sys.stdin.fileno())
172 os.write(pipe_w, request.headers['POST_VARS'])
174 os.execve(bin, opts, request.headers)
175 except:
176 print "Content-Type: text/plain\r\n\r\n"
178 print "*** INTERNAL ERROR ***"
179 print
181 print "Child Executing"
182 print "---------------"
183 print bin, opts
185 print
186 print "Palm Enviroment variables"
187 print "-------------------------"
188 for h in request.headers:
189 print h, "=", request.headers[h]
191 exit(1)
193 def get_pid(self):
194 return self._pid
196 def kill(self):
197 os.kill(self._pid, signal.SIGKILL)
199 class Request:
200 def __init__(self, resource):
201 self.resource = resource
202 self.headers = {}
204 def __str__(self):
205 ret = str(self.resource) + ' ' + str(self.headers);
206 return ret
208 def add_header(self, key, val):
209 self.headers[key] = val
211 def get(self, key):
212 return self.headers[key]