
Pisząc sceniaruszy testów obciążeniowych serwisów www często punktem wyjścia jest przygotowanie "tranzakcji" (używając tsungowej nomenklatury"), czyli listy plików dociąganych wraz z głównym dokumentem xhtml/html.
Na szczęście nowoczesne frameworki (między innymi Grinder, Tsung) dostarczają własne proxy umożliwiające przygotowanie takowej listy, często od razu w formacie używanym poprzez to narzędzie.
Co jednak zrobić w przypadku, kiedy potrzebujemy taką listę przygotować we własnym formacie, lub odrobinę zmodyfikowanym?
Wyjść mamy kilka, pierwszym najprostszym jest zainstalowanie dowolnego serwera proxy, między innymi squid lub tinyproxy. Squida nie polecam do tego celu - jest zdecydowanie zbyt potężny. Tinyproxy jest wygodny, małe i szybkie. Obydwa narzędzia przygotują piękną listę w formacie NCSA common log, który możemy łatwo sparsować...
Bardzo interesującym rozwiązaniem jest natomiast napisanie własnego proxy, dzięki czemu zyskamy:
Poniżej wklejam kawałek kodu, którego docstringi mówią wszystko - obsługuje on na początek jedynie metodę GET, łamie kilka standardów odnośnie protokołu HTTP - ale wszystko będzie w następnych częściach. Jako języka użyłem pythona - wydaje się on idealny, o zaletach nie będę się rozpisywał - poniższych kawałek kodu po odjęciu komentarzy zajmuje kilkanaście linijek i można go napisać w 30 minut...
#!/usr/bin/env python
"""
Simple HTTP Proxy - mainly used as additional to generate list of
downloaded additional statics files like css/js/imgs...
"""
from BaseHTTPServer import HTTPServer,BaseHTTPRequestHandler
### This is to use Threading module if Forking is not available
try:
from SocketServer import ForkingMixIn as IdoruMixIn
except:
from SocketServer import ThreadingMixIn as IdoruMixIn
import httplib
class IdoruHttpProxyHandler(BaseHTTPRequestHandler):
def do_GET(self):
"""
This one is for the HTTP GET method.
When client (mostly browser) send GET requests we catch it here,
and pass it to the destionation server, read the response
and serve it back...
"""
# headers dictionary for our proxy request
headers = {}
# we are copying here one dictionary to another, because in the
# future we will ad some conditional on some headers to avoid
# proxy them
for header in self.headers.keys():
headers[header] = self.headers[header]
# creating connection for proxy request
connection = httplib.HTTPConnection(headers['host'])
# reuqesting the page from the destination server
connection.request("GET", self.path, headers = headers)
# creating the response object
r1 = connection.getresponse()
response_headers = r1.getheaders()
# proxying status of the response
self.send_response(r1.status)
# copying dictionary, the reason to id is the same as above
[ self.send_header(*x) for x in response_headers ]
# reading response
text = r1.read()
# writing response back to browser
self.wfile.write('\n')
self.wfile.write(text)
self.wfile.close()
# closing connections
connection.close()
self.connection.close()
class IdoruHTTPServer(IdoruMixIn, HTTPServer):
""" Idoru HTTP Server """
pass
def main():
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-p", "--port", dest="port",
help="port on which iproxy will be listening", metavar="PORT",
default = 8000, type="int")
parser.add_option("-i", "--ip-address", dest='ip',
help="address on which iproxy will be listening", metavar="IP",
default = '127.0.0.1')
(options, args) = parser.parse_args()
print "Staring iproxy on %s:%s, please hit C c to exit..." % (options.ip,options.port)
httpd = IdoruHTTPServer((options.ip, options.port), IdoruHttpProxyHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
print "stopped..."
httpd.server_close()
if __name__ == '__main__':
# checking if we are run from the command line
main()
Jako pracę domową, polecam dodanie obsługi metody HEAD :)
W następnej części zaimplementujemy metody HEAD i POST.
Ostatnie odpowiedzi
1 rok 29 tygodni temu
2 lata 18 tygodni temu
2 lata 21 tygodni temu
2 lata 21 tygodni temu
2 lata 22 tygodnie temu