Commit 364fc8aa authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 19b3a99a
/*
http server doing some small text work on each http request.
Shows not only how runtime network reactor is good, but also how actual request
processing hooked to the reactor affects overal server handling capacity.
*/
package main
import (
"fmt"
"net/http"
)
const (
navytux = "navytux.spb.ru"
nexedi = "www.nexedi.com"
lab = "lab.nexedi.com"
erp5 = "www.erp5.com"
)
func abs8(v int8) int8 {
if v >= 0 {
return v
}
return -v
}
// whether character ch is close to string s.
// character is close to a string if it is close to any of characters in it
// character is close to a character if their distance <= 1
func isclose(ch byte, s string) bool {
for i := 0; i < len(s) ; i++ {
ch2 := s[i]
if abs8(int8(ch - ch2)) <= 1 {
return true
}
}
return false
}
type XClassifier struct {
nnavytux int
nnexedi int
nlab int
nerp5 int
ntotal int
}
func NewXClassifier() *XClassifier {
return &XClassifier{}
}
func (xc *XClassifier) nextChar(ch byte) {
if isclose(ch, navytux) {
xc.nnavytux += 1
}
if isclose(ch, nexedi) {
xc.nnexedi += 1
}
if isclose(ch, lab) {
xc.nlab += 1
}
if isclose(ch, erp5) {
xc.nerp5 += 1
}
xc.ntotal += 1
}
func handler(w http.ResponseWriter, r *http.Request) {
xc := NewXClassifier()
path := r.URL.Path
for i := range path {
xc.nextChar(path[i])
}
fmt.Fprintf(w, "%s:\t%d\n%s:\t%d\n%s:\t%d\n%s:\t%d\ntotal:\t%d\n",
navytux, xc.nnavytux, nexedi, xc.nnexedi,
lab, xc.nlab, erp5, xc.nerp5,
xc.ntotal)
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Serving on :25000")
http.ListenAndServe(":25000", nil)
}
#!/usr/bin/env python
"""
http server doing some small text work on each http request.
Shows not only how runtime network reactor is good, but also how actual request
processing hooked to the reactor affects overal server handling capacity.
Based on https://github.com/MagicStack/vmbench/blob/19b3a99a/servers/asyncio_http_server.py
Work on requests is between BEGIN/END PROCESSING marks.
Uvloop and httptools are activated ON by default.
"""
import argparse
import asyncio
import aiohttp
import aiohttp.server
from aiohttp import web
import sys
import httptools
import uvloop
from socket import *
PRINT = 0
_RESP_CACHE = {}
class HttpRequest:
__slots__ = ('_protocol', '_url', '_headers', '_version')
def __init__(self, protocol, url, headers, version):
self._protocol = protocol
self._url = url
self._headers = headers
self._version = version
class HttpResponse:
__slots__ = ('_protocol', '_request', '_headers_sent')
def __init__(self, protocol, request):
self._protocol = protocol
self._request = request
self._headers_sent = False
def write(self, data):
self._protocol._transport.write(b''.join([
'HTTP/{} 200 OK\r\n'.format(
self._request._version).encode('latin-1'),
b'Content-Type: text/plain\r\n',
'Content-Length: {}\r\n'.format(len(data)).encode('latin-1'),
b'\r\n',
data
]))
class HttpProtocol(asyncio.Protocol):
__slots__ = ('_loop',
'_transport', '_current_request', '_current_parser',
'_current_url', '_current_headers')
def __init__(self, *, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
self._loop = loop
self._transport = None
self._current_request = None
self._current_parser = None
self._current_url = None
self._current_headers = None
def on_url(self, url):
self._current_url = url
def on_header(self, name, value):
self._current_headers.append((name, value))
def on_headers_complete(self):
self._current_request = HttpRequest(
self, self._current_url, self._current_headers,
self._current_parser.get_http_version())
self._loop.call_soon(
self.handle, self._current_request,
HttpResponse(self, self._current_request))
####
def connection_made(self, transport):
self._transport = transport
sock = transport.get_extra_info('socket')
try:
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
except (OSError, NameError):
pass
def connection_lost(self, exc):
self._current_request = self._current_parser = None
def data_received(self, data):
if self._current_parser is None:
assert self._current_request is None
self._current_headers = []
self._current_parser = httptools.HttpRequestParser(self)
self._current_parser.feed_data(data)
def handle(self, request, response):
parsed_url = httptools.parse_url(self._current_url)
# >>> BEGIN PROCESSING
xc = XClassifier()
for char in parsed_url.path:
xc.nextChar(char)
resp = b'%s:\t%d\n%s:\t%d\n%s:\t%d\n%s:\t%d\ntotal:\t%d\n' % (
navytux, xc.nnavytux, nexedi, xc.nnexedi,
lab, xc.nlab, erp5, xc.nerp5,
xc.ntotal)
response.write(resp)
if not self._current_parser.should_keep_alive():
self._transport.close()
self._current_parser = None
self._current_request = None
navytux = b'navytux.spb.ru'
nexedi = b'www.nexedi.com'
lab = b'lab.nexedi.com'
erp5 = b'www.erp5.com'
# whether character ch is close to string s.
# character is close to a string if it is close to any of characters in it
# character is close to a character if their distance <= 1
def isclose(ch, s):
for ch2 in s:
if abs(ch - ch2) <= 1:
return True
return False
class XClassifier:
def __init__(self):
self.nnavytux = 0
self.nnexedi = 0
self.nlab = 0
self.nerp5 = 0
self.ntotal = 0
def nextChar(self, ch):
if isclose(ch, navytux):
self.nnavytux += 1
if isclose(ch, nexedi):
self.nnexedi += 1
if isclose(ch, lab):
self.nlab += 1
if isclose(ch, erp5):
self.nerp5 += 1
self.ntotal += 1
# <<< END PROCESSING
def abort(msg):
print(msg, file=sys.stderr)
sys.exit(1)
def aiohttp_server(loop, addr):
async def handle(request):
payload_size = int(request.match_info.get('size', 1024))
resp = _RESP_CACHE.get(payload_size)
if resp is None:
resp = b'X' * payload_size
_RESP_CACHE[payload_size] = resp
return web.Response(body=resp)
app = web.Application(loop=loop)
app.router.add_route('GET', '/{size}', handle)
app.router.add_route('GET', '/', handle)
handler = app.make_handler()
server = loop.create_server(handler, *addr)
return server
def httptools_server(loop, addr):
return loop.create_server(lambda: HttpProtocol(loop=loop), *addr)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
#parser.add_argument('--type', default='asyncio+aiohttp', action='store')
parser.add_argument('--type', default='uvloop+httptools', action='store')
parser.add_argument('--addr', default='127.0.0.1:25000', type=str)
args = parser.parse_args()
if args.type:
parts = args.type.split('+')
if len(parts) > 1:
loop_type = parts[0]
server_type = parts[1]
else:
server_type = args.type
if server_type in {'aiohttp', 'httptools'}:
if not loop_type:
loop_type = 'asyncio'
else:
loop_type = None
if loop_type not in {'asyncio', 'uvloop'}:
abort('unrecognized loop type: {}'.format(loop_type))
if server_type not in {'aiohttp', 'httptools'}:
abort('unrecognized server type: {}'.format(server_type))
if loop_type:
loop = globals()[loop_type].new_event_loop()
else:
loop = None
print('using {} loop: {!r}'.format(loop_type, loop))
print('using {} HTTP server'.format(server_type))
if loop:
asyncio.set_event_loop(loop)
loop.set_debug(False)
unix = False
if args.addr.startswith('file:'):
unix = True
addr = args.addr[5:]
else:
addr = args.addr.split(':')
addr[1] = int(addr[1])
addr = tuple(addr)
server_factory = globals()['{}_server'.format(server_type)]
print('serving on: {}'.format(addr))
if loop:
server = loop.run_until_complete(server_factory(loop, addr))
try:
loop.run_forever()
finally:
server.close()
loop.close()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment