2 Created on Aug 15, 2017
15 from jsonschema import validate
19 import SimpleHTTPServer
22 from cStringIO import StringIO
24 from StringIO import StringIO
31 sz = DcaeVariables.VESEventQ.qsize()
34 self.evtQueue.get_nowait()
40 if DcaeVariables.VESEventQ is not None:
42 DcaeVariables.VESEventQ.put(evt)
44 except Exception as e:
50 def deque_event(wait_sec=25):
51 if DcaeVariables.IsRobotRun:
54 evt = DcaeVariables.VESEventQ.get(True, wait_sec)
56 except Exception as e:
57 if DcaeVariables.IsRobotRun:
61 print("DMaaP Event dequeue timeout")
65 class DMaaPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
68 self.send_response(405)
73 # Parse the form data posted
75 form = cgi.FieldStorage(
78 environ={'REQUEST_METHOD':'POST',
79 'CONTENT_TYPE':self.headers['Content-Type'],
83 form = cgi.FieldStorage(
86 environ={"REQUEST_METHOD": "POST"})
88 for item in form.list:
89 print "%s=%s" % (item.name, item.value)
93 if 'POST' not in self.requestline:
98 if '/eventlistener/v5' not in self.requestline and '/eventlistener/v5/eventBatch' not in self.requestline and \
99 '/eventlistener/v5/clientThrottlingState' not in self.requestline:
104 if 'Y29uc29sZTpaakprWWpsbE1qbGpNVEkyTTJJeg==' not in str(self.headers):
109 content_len = int(self.headers.getheader('content-length', 0))
110 post_body = self.rfile.read(content_len)
112 indx = post_body.index("{")
114 post_body = post_body[indx:]
116 if not enque_event(post_body):
117 print "enque event fails"
121 if EvtSchema is None:
122 with open(DcaeVariables.CommonEventSchemaV5) as opened_file:
123 EvtSchema = json.load(opened_file)
124 decoded_body = json.loads(post_body)
125 jsonschema.validate(decoded_body, EvtSchema)
130 if not DcaeVariables.IsRobotRun:
131 print ("Response Message:")
136 "description" : "Success",
138 "$ref" : "#/definitions/DR_Pub"
142 rspStr = "{'responses' : {'200' : {'description' : 'Success'}}}"
143 rspStr1 = "{'count': 1, 'serverTimeMs': 3}"
148 if 'clientThrottlingState' in self.requestline:
149 self.send_response(204)
151 self.send_response(200)
152 self.send_header('Content-Type', 'application/json')
154 self.wfile.write("{'count': 1, 'serverTimeMs': 3}")
157 self.send_response(resp_code)
161 self.wfile.write('Client: %s\n' % str(self.client_address))
162 self.wfile.write('User-agent: %s\n' % str(self.headers['user-agent']))
163 self.wfile.write('Path: %s\n' % self.path)
164 self.wfile.write('Form data:\n')
167 # Echo back information about what was posted in the form
168 for field in form.keys():
169 field_item = form[field]
170 if field_item.filename:
171 # The field contains an uploaded file
172 file_data = field_item.file.read()
173 file_len = len(file_data)
175 self.wfile.write('\tUploaded %s as "%s" (%d bytes)\n' % \
176 (field, field_item.filename, file_len))
179 self.wfile.write('\t%s=%s\n' % (field, form[field].value))
184 """Serve a GET request."""
188 self.copyfile(f, self.wfile)
193 """Serve a HEAD request."""
199 """Common code for GET and HEAD commands.
201 This sends the response code and MIME headers.
203 Return value is either a file object (which has to be copied
204 to the outputfile by the caller unless the command was HEAD,
205 and must be closed by the caller under all circumstances), or
206 None, in which case the caller has nothing further to do.
209 path = self.translate_path(self.path)
210 if os.path.isdir(path):
211 parts = urlparse.urlsplit(self.path)
212 if not parts.path.endswith('/'):
213 # redirect browser - doing basically what apache does
214 self.send_response(301)
215 new_parts = (parts[0], parts[1], parts[2] + '/',
217 new_url = urlparse.urlunsplit(new_parts)
218 self.send_header("Location", new_url)
221 for index in "index.html", "index.htm":
222 index = os.path.join(path, index)
223 if os.path.exists(index):
227 return self.list_directory(path)
228 ctype = self.guess_type(path)
230 # Always read in binary mode. Opening files in text mode may cause
231 # newline translations, making the actual size of the content
232 # transmitted *less* than the content-length!
235 self.send_error(404, "File not found")
238 self.send_response(200)
239 self.send_header("Content-type", ctype)
240 fs = os.fstat(f.fileno())
241 self.send_header("Content-Length", str(fs[6]))
242 self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
249 def list_directory(self, path):
250 """Helper to produce a directory listing (absent index.html).
252 Return value is either a file object, or None (indicating an
253 error). In either case, the headers are sent, making the
254 interface the same as for send_head().
258 list_dir = os.listdir(path)
260 self.send_error(404, "No permission to list directory")
262 list_dir.sort(key=lambda a: a.lower())
264 displaypath = cgi.escape(urllib.unquote(self.path))
265 f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
266 f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
267 f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
268 f.write("<hr>\n<ul>\n")
269 for name in list_dir:
270 fullname = os.path.join(path, name)
271 displayname = linkname = name
272 # Append / for directories or @ for symbolic links
273 if os.path.isdir(fullname):
274 displayname = name + "/"
275 linkname = name + "/"
276 if os.path.islink(fullname):
277 displayname = name + "@"
278 # Note: a link to a directory displays with @ and links with /
279 f.write('<li><a href="%s">%s</a>\n'
280 % (urllib.quote(linkname), cgi.escape(displayname)))
281 f.write("</ul>\n<hr>\n</body>\n</html>\n")
284 self.send_response(200)
285 encoding = sys.getfilesystemencoding()
286 self.send_header("Content-type", "text/html; charset=%s" % encoding)
287 self.send_header("Content-Length", str(length))
292 def translate_path(path):
293 """Translate a /-separated PATH to the local filename syntax.
295 Components that mean special things to the local file system
296 (e.g. drive or directory names) are ignored. (XXX They should
297 probably be diagnosed.)
300 # abandon query parameters
301 path = path.split('?', 1)[0]
302 path = path.split('#', 1)[0]
303 # Don't forget explicit trailing slash when normalizing. Issue17324
304 trailing_slash = path.rstrip().endswith('/')
305 path = posixpath.normpath(urllib.unquote(path))
306 words = path.split('/')
307 words = filter(None, words)
310 if os.path.dirname(word) or word in (os.curdir, os.pardir):
311 # Ignore components that are not a simple file/directory name
313 path = os.path.join(path, word)
319 def copyfile(source, outputfile):
320 """Copy all data between two file objects.
322 The SOURCE argument is a file object open for reading
323 (or anything with a read() method) and the DESTINATION
324 argument is a file object open for writing (or
325 anything with a write() method).
327 The only reason for overriding this would be to change
328 the block size or perhaps to replace newlines by CRLF
329 -- note however that this the default server uses this
330 to copy binary data as well.
333 shutil.copyfileobj(source, outputfile)
335 def guess_type(self, path):
336 """Guess the type of a file.
338 Argument is a PATH (a filename).
340 Return value is a string of the form type/subtype,
341 usable for a MIME Content-type header.
343 The default implementation looks the file's extension
344 up in the table self.extensions_map, using application/octet-stream
345 as a default; however it would be permissible (if
346 slow) to look inside the data to make a better guess.
350 base, ext = posixpath.splitext(path)
351 if ext in self.extensions_map:
352 return self.extensions_map[ext]
354 if ext in self.extensions_map:
355 return self.extensions_map[ext]
357 return self.extensions_map['']
359 if not mimetypes.inited:
360 mimetypes.init() # try to read system mime.types
361 extensions_map = mimetypes.types_map.copy()
362 extensions_map.update({
363 '': 'application/octet-stream', # Default
370 def test(handler_class=DMaaPHandler, server_class=BaseHTTPServer.HTTPServer, protocol="HTTP/1.0", port=3904):
371 print "Load event schema file: " + DcaeVariables.CommonEventSchemaV5
372 with open(DcaeVariables.CommonEventSchemaV5) as opened_file:
374 EvtSchema = json.load(opened_file)
376 server_address = ('', port)
378 handler_class.protocol_version = protocol
379 httpd = server_class(server_address, handler_class)
383 DcaeVariables.HTTPD = httpd
385 sa = httpd.socket.getsockname()
386 print "Serving HTTP on", sa[0], "port", sa[1], "..."
387 # httpd.serve_forever()
390 def _main_(handler_class=DMaaPHandler, server_class=BaseHTTPServer.HTTPServer, protocol="HTTP/1.0"):
393 port = int(sys.argv[1])
397 print "Load event schema file: " + DcaeVariables.CommonEventSchemaV5
398 with open(DcaeVariables.CommonEventSchemaV5) as opened_file:
400 EvtSchema = json.load(opened_file)
402 server_address = ('', port)
404 handler_class.protocol_version = protocol
405 httpd = server_class(server_address, handler_class)
407 sa = httpd.socket.getsockname()
408 print "Serving HTTP on", sa[0], "port", sa[1], "..."
409 httpd.serve_forever()
412 if __name__ == '__main__':