Commits

Ginés Martínez Sánchez committed d11f314 Draft

developing http server

Comments (0)

Files changed (6)

ginsfsm/examples/http/http_server_echo.py

 from ginsfsm.gobj import GObj
 from ginsfsm.gaplic import GAplic
 from ginsfsm.protocols.http.server.c_http_server import GHttpServer
+from ginsfsm.protocols.http.common.response import HttpSimpleOkResponse
 
 
 def ac_channel_opened(self, event):
 
 
 def ac_request(self, event):
+    print "======> channel request"
+    channel = event.source[-1]
     request = event.request
-    print "======> channel request"
-    print request
+    response = HttpSimpleOkResponse(
+        request,
+        'Caraculo\r\nCaraculo\r\nCaraculo\r\n'
+    )
+    self.send_event(channel, 'EV_HTTP_RESPONSE', response=response)
 
 
 HTTP_ECHO_FSM = {
             host='0.0.0.0',
             port=8000,
             subscriber=self,
-            inactivity_timeout=2,
+            inactivity_timeout=10,
             responseless_timeout=2,
-            maximum_simultaneous_requests=1,
+            maximum_simultaneous_requests=0,
         )
 
         if self.verbose > 0:

ginsfsm/protocols/http/common/parser.py

     # Other attributes: first_line, header, headers, command, uri, version,
     # path, query, fragment
 
-    def __init__(self, url_scheme,
-                 inbuf_overflow=524288,
-                 max_request_header_size=262144,
-                 max_request_body_size=1073741824):
+    def __init__(self, channel):
         # headers is a mapping containing keys translated to uppercase
         # with dashes turned into underscores.
-        self.url_scheme = url_scheme
-        self.inbuf_overflow = inbuf_overflow
-        self.max_request_header_size = max_request_header_size
-        self.max_request_body_size = max_request_body_size
+        self.channel = channel
+        self.url_scheme = channel.url_scheme
+        self.inbuf_overflow = channel.inbuf_overflow
+        self.max_request_header_size = channel.max_request_header_size
+        self.max_request_body_size = channel.max_request_body_size
         self.headers = {}
 
         # these variables were in the class section

ginsfsm/protocols/http/common/response.py

 
 import logging
 import socket
-import sys
 import time
 from ginsfsm.deferred import DeferredInterrupt
 
 
 
 class HttpResponse(object):
-    def __init__(self, identity, gsock, request, ext_event=None):
-        self.identity = identity
-        self.gsock = gsock
+    def __init__(self, request):
         self.request = request
-        self.ext_event = ext_event
+        self.gsock = request.channel.gsock
         self.response_headers = []
         version = request.version
         if version not in ('1.0', '1.1'):
 
         # Set the Server and Date field, if not yet specified. This is needed
         # if the server is used as a proxy.
-        ident = self.identity
+        ident = self.request.channel.identity
         if not server_header:
             response_headers.append(('Server', ident))
         else:
 class HttpErrorResponse(HttpResponse):
     """ An error task produces an error response """
 
-    def __init__(self, identity, gsock, request):
-        HttpResponse.__init__(self, identity, gsock, request)
+    def __init__(self, request):
+        HttpResponse.__init__(self, request)
         self.complete = True
 
     def execute(self):
         self.response_headers.append(('Connection', 'close'))
         self.close_on_finish = True
         self.write(tobytes(body))
+
+
+class HttpSimpleOkResponse(HttpResponse):
+    """ An simple OK response """
+
+    def __init__(self, request, body, toclose=True):
+        HttpResponse.__init__(self, request)
+        self.complete = True
+        self.body = body
+        self.toclose = toclose
+
+    def execute(self):
+        cl = len(self.body)
+        self.content_length = cl
+        self.response_headers.append(('Content-Length', str(cl)))
+        self.response_headers.append(('Content-Type', 'text/plain'))
+        if self.toclose:
+            self.response_headers.append(('Connection', 'close'))
+            self.close_on_finish = True
+        self.write(tobytes(self.body))

ginsfsm/protocols/http/server/c_http_clisrv.py

     new_request = self.current_request
     while data:
         if new_request is None:
-            new_request = HTTPRequestParser(
-                url_scheme=self.url_scheme,
-                inbuf_overflow=self.inbuf_overflow,
-                max_request_header_size=self.max_request_header_size,
-                max_request_body_size=self.max_request_body_size)
+            new_request = HTTPRequestParser(self)
         n = new_request.received(data)
         if new_request.expect_continue and new_request.headers_finished:
             # guaranteed by parser to be a 1.1 new_request
 
 def ac_dequeue_request(self, event):
     if self.responding_request:
-        self.logger.exception('ERROR: responding_request MUST be None')
+        self.logger.exception('Internal ERROR!!!: '
+                              'responding_request MUST be None')
     if len(self.dl_requests):
         self.responding_request = self.dl_requests.popleft()
         self.send_event(self, 'EV_HTTP_REQUEST')
 
 
 def ac_http_response(self, event):
+    response = event.response
     self.stop_responseless_timer()
     # send response to client
+    response.service()
 
     # pull the request queue
     self.post_event(self, 'EV_DEQUEUE_REQUEST')
     if not self.gsock:
         return
 
-    body = ('The server is busy. '
+    body = ('Response Timeout. The server is busy. '
             'Please re-try your request in a few moments.'
     )
-    request = HTTPRequestParser(
-        url_scheme=self.url_scheme
-    )
+    request = HTTPRequestParser(self)
     request.error = InternalServerError(body)
-    task = HttpErrorResponse(self.identity, self.gsock, request)
-    task.service()
+    response = HttpErrorResponse(request)
+    response.service()
 
 
 GHTTPCLISRV_FSM = {
     'gsock': [None, None, 0, None,
         "partner gsock."
         ],
-    'maximum_simultaneous_requests': [int, 10, 0, None,
+    'maximum_simultaneous_requests': [int, 0, 0, None,
         "maximum simultaneous requests."
         ],
     'identity': [str, 'ginsfsm', 0, None,
        :gconfig: GHTTPCLISRV_GCONFIG
 
     *Top Output-Events:*
-        * :attr:`'EV_HTTP_CHANNEL_OPENED'`: new client *http channel*.
-          Event attributes:
+        * :attr:`'EV_HTTP_CHANNEL_OPENED'`: new http client.
 
-            * ``channel``: gsock attending the socket connection.
+        * :attr:`'EV_HTTP_CHANNEL_CLOSED'`: http client closed.
 
-        * :attr:`'EV_HTTP_CHANNEL_CLOSED'`: *http channel* closed.
-          Event attributes:
-
-            * ``channel``: gsock closing.
-
-        * :attr:`'EV_HTTP_REQUEST'`: new *http request*.
+        * :attr:`'EV_HTTP_REQUEST'`: new http request.
 
           Event attributes:
 
     def enqueue_request(self, new_request):
         # TODO: check limit queue size
         self.dl_requests.append(new_request)
-        if len(self.dl_requests) >= self.maximum_simultaneous_requests:
+        if self.maximum_simultaneous_requests > 0 and \
+                len(self.dl_requests) > self.maximum_simultaneous_requests:
             # Close the channel by maximum simultaneous requests reached.
             body = 'Please change your behavior.' \
                 ' You have reached the maximum simultaneous requests (%d).' % (
                     self.maximum_simultaneous_requests)
-            request = HTTPRequestParser(
-                url_scheme=self.url_scheme
-            )
+            request = HTTPRequestParser(self)
             request.error = InternalServerError(body)
             task = HttpErrorResponse(self.identity, self.gsock, request)
             task.service()

ginsfsm/protocols/http/server/c_http_server.py

     'origins': [None, None, 0, None,
         "TODO:list of (host, port) tuples allowed to connect from"],
 
-    'maximum_simultaneous_requests': [int, 10, 0, None,
+    'maximum_simultaneous_requests': [int, 0, 0, None,
         "maximum simultaneous requests."
         ],
     'identity': [str, 'ginsfsm', 0, None,

ginsfsm/wsgi/utilities.py

 
 logger = logging.getLogger('waitress')
 
+
 def find_double_newline(s):
     """Returns the position just after a double newline in the given string."""
     pos1 = s.find(b'\n\r\n')  # One kind of double newline
     else:
         return pos2
 
+
 def concat(*args):
     return ''.join(args)
 
+
 def join(seq, field=' '):
     return field.join(seq)
 
+
 def group(s):
     return '(' + s + ')'
 
-short_days = ['sun','mon','tue','wed','thu','fri','sat']
-long_days = ['sunday','monday','tuesday','wednesday',
-             'thursday','friday','saturday']
+short_days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
+long_days = ['sunday', 'monday', 'tuesday', 'wednesday',
+             'thursday', 'friday', 'saturday']
 
 short_day_reg = group(join(short_days, '|'))
 long_day_reg = group(join(long_days, '|'))
 
 hms_reg = join(3 * [group('[0-9][0-9]')], ':')
 
-months = ['jan','feb','mar','apr','may','jun','jul',
-          'aug','sep','oct','nov','dec']
+months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul',
+          'aug', 'sep', 'oct', 'nov', 'dec']
 
 monmap = {}
 for i in range(12):
-    monmap[months[i]] = i+1
+    monmap[months[i]] = i + 1
 
 months_reg = group(join(months, '|'))
 
 
 # rfc822 format
 rfc822_date = join(
-        [concat (short_day_reg,','),            # day
+        [concat(short_day_reg, ','),            # day
          group('[0-9][0-9]?'),                  # date
          months_reg,                            # month
          group('[0-9]+'),                       # year
 
 rfc822_reg = re.compile(rfc822_date)
 
+
 def unpack_rfc822(m):
     g = m.group
     return (
 
     # rfc850 format
 rfc850_date = join(
-        [concat(long_day_reg,','),
+        [concat(long_day_reg, ','),
          join(
-                 [group ('[0-9][0-9]?'),
+                 [group('[0-9][0-9]?'),
                   months_reg,
-                  group ('[0-9]+')
+                  group('[0-9]+')
                   ],
                  '-'
                  ),
         )
 
 rfc850_reg = re.compile(rfc850_date)
+
+
 # they actually unpack the same way
 def unpack_rfc850(m):
     g = m.group
     yr = g(4)
     if len(yr) == 2:
-        yr = '19'+yr
+        yr = '19' + yr
     return (
             int(yr),           # year
             monmap[g(3)],        # month
 monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
 
+
 def build_http_date(when):
     year, month, day, hh, mm, ss, wd, y, z = time.gmtime(when)
     return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
             day, monthname[month], year,
             hh, mm, ss)
 
+
 def parse_http_date(d):
     d = d.lower()
     m = rfc850_reg.match(d)
             return 0
     return retval
 
+
 class logging_dispatcher(asyncore.dispatcher):
     logger = logger
+
     def log_info(self, message, type='info'):
         severity = {
             'info': logging.INFO,
             }
         self.logger.log(severity.get(type, logging.INFO), message)
 
+
 class Error(object):
     def __init__(self, body):
         self.body = body
 
+
 class BadRequest(Error):
     code = 400
     reason = 'Bad Request'
 
+
 class RequestHeaderFieldsTooLarge(BadRequest):
     code = 431
     reason = 'Request Header Fields Too Large'
 
+
 class RequestEntityTooLarge(BadRequest):
     code = 413
     reason = 'Request Entity Too Large'
 
+
 class InternalServerError(Error):
     code = 500
     reason = 'Internal Server Error'
-        
-