source: ogAgent-Git/src/opengnsys/httpserver.py @ e777421

decorare-oglive-methodsfixes-winlgromero-filebeatmainmodulesnew-browserno-ptt-paramogadmcliogadmclient-statusogagent-jobsogagent-macosogcore1oglogoglog2override-moduleping1ping2ping3ping4py3-winpython3report-progresstlsunification2unification3versionswindows-fixes
Last change on this file since e777421 was 2350389, checked in by Ramón M. Gómez <ramongomez@…>, 5 years ago

#940: Fix HTTP header bug

Function send-header needs str, not `int; adding some PEP 8 code clean up.

  • Property mode set to 100644
File size: 5.4 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2015 Virtual Cable S.L.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without modification,
7# are permitted provided that the following conditions are met:
8#
9#    * Redistributions of source code must retain the above copyright notice,
10#      this list of conditions and the following disclaimer.
11#    * Redistributions in binary form must reproduce the above copyright notice,
12#      this list of conditions and the following disclaimer in the documentation
13#      and/or other materials provided with the distribution.
14#    * Neither the name of Virtual Cable S.L. nor the names of its contributors
15#      may be used to endorse or promote products derived from this software
16#      without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28"""
29@author: Adolfo Gómez, dkmaster at dkmon dot com
30"""
31
32
33import json
34import ssl
35import threading
36from six.moves.socketserver import ThreadingMixIn  # @UnresolvedImport
37from six.moves.BaseHTTPServer import BaseHTTPRequestHandler  # @UnresolvedImport
38from six.moves.BaseHTTPServer import HTTPServer  # @UnresolvedImport
39from six.moves.urllib.parse import unquote  # @UnresolvedImport
40
41from .utils import exceptionToMessage
42from .certs import createSelfSignedCert
43from .log import logger
44
45
46class HTTPServerHandler(BaseHTTPRequestHandler):
47    service = None
48    protocol_version = 'HTTP/1.0'
49    server_version = 'OpenGnsys Agent Server'
50    sys_version = ''
51   
52    def sendJsonError(self, code, message):
53        self.send_response(code)
54        self.send_header('Content-type', 'application/json')
55        self.end_headers()
56        self.wfile.write(str.encode(json.dumps({'error': message})))
57        return
58
59    def sendJsonResponse(self, data):
60        self.send_response(200)
61        data = json.dumps(data)
62        self.send_header('Content-type', 'application/json')
63        self.send_header('Content-Length', str(len(data)))
64        self.end_headers()
65        # Send the html message
66        self.wfile.write(str.encode(data))
67
68    def parseUrl(self):
69        """
70        Very simple path & params splitter
71        """
72        path = self.path.split('?')[0][1:].split('/')
73       
74        try:
75            params = dict((v[0], unquote(v[1])) for v in (v.split('=') for v in self.path.split('?')[1].split('&')))
76        except Exception:
77            params = {}
78
79        for v in self.service.modules:
80            if v.name == path[0]:  # Case Sensitive!!!!
81                return v, path[1:], params
82           
83        return None, path, params
84   
85    def notifyMessage(self, module, path, get_params, post_params):
86        """
87        Locates witch module will process the message based on path (first folder on url path)
88        """
89        try:
90            data = module.processServerMessage(path, get_params, post_params, self)
91            self.sendJsonResponse(data)
92        except Exception as e:
93            logger.exception()
94            self.sendJsonError(500, exceptionToMessage(e))
95           
96    def do_GET(self):
97        module, path, params = self.parseUrl()
98       
99        self.notifyMessage(module, path, params, None)
100       
101    def do_POST(self):
102        module, path, get_params = self.parseUrl()
103        post_params = None
104
105        # Tries to get JSON content (UTF-8 encoded)
106        try:
107            length = int(self.headers.get('content-length'))
108            content = self.rfile.read(length).decode('utf-8')
109            logger.debug('length: {0}, content >>{1}<<'.format(length, content))
110            post_params = json.loads(content)
111        except Exception as e:
112            self.sendJsonError(500, exceptionToMessage(e))
113           
114        self.notifyMessage(module, path, get_params, post_params)
115
116    def log_error(self, fmt, *args):
117        logger.error('HTTP ' + fmt % args)
118       
119    def log_message(self, fmt, *args):
120        logger.info('HTTP ' + fmt % args)
121       
122
123class HTTPThreadingServer(ThreadingMixIn, HTTPServer):
124    pass
125
126
127class HTTPServerThread(threading.Thread):
128    def __init__(self, address, service):
129        super(self.__class__, self).__init__()
130
131        HTTPServerHandler.service = service  # Keep tracking of service so we can intercact with it
132
133        self.certFile = createSelfSignedCert()
134        self.server = HTTPThreadingServer(address, HTTPServerHandler)
135        self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
136       
137        logger.debug('Initialized HTTPS Server thread on {}'.format(address))
138
139    def getServerUrl(self):
140        return 'https://{}:{}/'.format(self.server.server_address[0], self.server.server_address[1])
141
142    def stop(self):
143        self.server.shutdown()
144
145    def run(self):
146        self.server.serve_forever()
Note: See TracBrowser for help on using the repository browser.